1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 #include <QByteArray>
8 #include <QDataStream>
9 #include <QDebug>
10 #include <QFile>
11 #include <QFileInfo>
12 #include <QRegExp>
13
14 #include "cmsettings.h"
15 #include "colormgmt/sccolormgmtengine.h"
16 #include "scclocale.h"
17 #include "scpaths.h"
18 #include "scribuscore.h"
19 #include "scimgdataloader_ps.h"
20 #include "sctextstream.h"
21 #include "prefsmanager.h"
22 #include "util.h"
23 #include "util_formats.h"
24 #include "util_ghostscript.h"
25 #include "util_math.h"
26 #include "scimage.h"
27
28 extern "C"
29 {
30 #define XMD_H // shut JPEGlib up
31 #if defined(Q_OS_UNIXWARE)
32 # define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
33 #endif
34 #include <jpeglib.h>
35 #include <jerror.h>
36 #include <csetjmp>
37 #undef HAVE_STDLIB_H
38 #ifdef const
39 # undef const // remove crazy C hackery in jconfig.h
40 #endif
41 }
42
ScImgDataLoader_PS()43 ScImgDataLoader_PS::ScImgDataLoader_PS() :
44 m_isDCS1(false),
45 m_isDCS2(false),
46 m_isDCS2multi(false),
47 m_isPhotoshop(false),
48 m_hasPhotoshopImageData(false),
49 m_doThumbnail(false),
50 m_hasThumbnail(false),
51 m_inTrailer(false),
52 m_BBoxInTrailer(false),
53 m_isRotated(false),
54 m_psXSize(0),
55 m_psYSize(0),
56 m_psDepth(0),
57 m_psMode(0),
58 m_psChannel(0),
59 m_psBlock(0),
60 m_psDataType(0)
61 {
62 initSupportedFormatList();
63 }
64
initialize()65 void ScImgDataLoader_PS::initialize()
66 {
67 m_doThumbnail = false;
68 m_hasThumbnail = false;
69
70 ScImgDataLoader::initialize();
71 }
72
initSupportedFormatList()73 void ScImgDataLoader_PS::initSupportedFormatList()
74 {
75 m_supportedFormats.clear();
76 m_supportedFormats<<"ps"<<"eps"<<"epsi";
77 }
78
loadEmbeddedProfile(const QString & fn,int)79 void ScImgDataLoader_PS::loadEmbeddedProfile(const QString& fn, int /* page */)
80 {
81 m_embeddedProfile.resize(0);
82 m_profileComponents = 0;
83 if ( !QFile::exists(fn) )
84 return;
85 QFile f(fn);
86 if (!f.open(QIODevice::ReadOnly))
87 return;
88
89 QString tmp;
90 QDataStream ts(&f);
91 while (!ts.atEnd())
92 {
93 tmp = readLineFromDataStream(ts);
94 if (tmp.startsWith("%%BeginICCProfile:"))
95 {
96 QByteArray psdata;
97 while (!ts.atEnd())
98 {
99 tmp = readLineFromDataStream(ts);
100 for (int a = 2; a < tmp.length(); a += 2)
101 {
102 bool ok;
103 ushort data = tmp.midRef(a, 2).toUShort(&ok, 16);
104 psdata.resize(psdata.size()+1);
105 psdata[psdata.size()-1] = data;
106 }
107 if (tmp.startsWith("%%EndICCProfile"))
108 {
109 ScColorMgmtEngine engine(ScCore->defaultEngine);
110 ScColorProfile prof = engine.openProfileFromMem(psdata);
111 if (prof)
112 {
113 if (prof.colorSpace() == ColorSpace_Rgb)
114 m_profileComponents = 3;
115 if (prof.colorSpace() == ColorSpace_Cmyk)
116 m_profileComponents = 4;
117 m_imageInfoRecord.profileName = prof.productDescription();
118 m_imageInfoRecord.embeddedProfileName = m_imageInfoRecord.profileName;
119 m_imageInfoRecord.isEmbedded = true;
120 m_embeddedProfile = psdata;
121 }
122 break;
123 }
124 }
125 }
126 }
127 }
128
scanForFonts(const QString & fn)129 void ScImgDataLoader_PS::scanForFonts(const QString& fn)
130 {
131 QFile f(fn);
132 if (!f.open(QIODevice::ReadOnly))
133 return;
134 QDataStream ts(&f);
135 QString tmp;
136 while (!ts.atEnd())
137 {
138 tmp = readLineFromDataStream(ts);
139 if (tmp.startsWith("%%BeginFont:"))
140 {
141 tmp = tmp.remove("%%BeginFont:");
142 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
143 QString tmp2;
144 ts2 >> tmp2;
145 m_FontListe.removeAll(tmp2);
146 }
147 }
148 }
149
parseData(const QString & fn)150 bool ScImgDataLoader_PS::parseData(const QString& fn)
151 {
152 QString tmp, FarNam;
153 ScColor cc;
154 double x, y, b, h, c, m, k;
155 bool found = false;
156 m_isDCS1 = false;
157 m_isDCS2 = false;
158 m_isDCS2multi = false;
159 m_isPhotoshop = false;
160 m_hasPhotoshopImageData = false;
161 m_hasThumbnail = false;
162 m_inTrailer = false;
163 m_BBoxInTrailer = false;
164 m_isRotated = false;
165 int plateCount = 0;
166 uint startPos = 0;
167 m_FontListe.clear();
168 QFile f(fn);
169 if (f.open(QIODevice::ReadOnly))
170 {
171 QByteArray tempBuf(9, ' ');
172 f.read(tempBuf.data(), 8);
173 if (getDouble(tempBuf.mid(0, 4), true) == 0xC5D0D3C6)
174 {
175 startPos = getDouble(tempBuf.mid(4, 4), false);
176 if (m_doThumbnail)
177 {
178 f.seek(0);
179 QByteArray tmp2buf(29, ' ');
180 f.read(tmp2buf.data(), 28);
181 uint thumbStart = 0;
182 thumbStart = tmp2buf[20] & 0xff;
183 thumbStart |= (tmp2buf[21] << 8) & 0xff00;
184 thumbStart |= (tmp2buf[22] << 16) & 0xff0000;
185 thumbStart |= (tmp2buf[23] << 24) & 0xff000000;
186 uint thumbLen = 0;
187 thumbLen = tmp2buf[24] & 0xff;
188 thumbLen |= (tmp2buf[25] << 8) & 0xff00;
189 thumbLen |= (tmp2buf[26] << 16) & 0xff0000;
190 thumbLen |= (tmp2buf[27] << 24) & 0xff000000;
191 if (thumbLen != 0)
192 {
193 QByteArray imgc(thumbLen, ' ');
194 f.seek(thumbStart);
195 f.read(imgc.data(), thumbLen);
196 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "preview.tiff");
197 QFile f2(tmpFile);
198 if (f2.open(QIODevice::WriteOnly))
199 f2.write(imgc.data(), thumbLen);
200 f2.close();
201 imgc.resize(0);
202 ScImage thum;
203 CMSettings cms(nullptr, "", Intent_Perceptual);
204 cms.allowColorManagement(false);
205 bool mode = true;
206 if (thum.loadPicture(tmpFile, 1, cms, ScImage::RGBData, 72, &mode))
207 {
208 m_imageInfoRecord.exifDataValid = true;
209 m_imageInfoRecord.exifInfo.thumbnail = thum.qImage().copy();
210 }
211 QFile::remove(tmpFile);
212 m_hasThumbnail = true;
213 }
214 }
215 }
216 bool psFound = false;
217 bool isAtend = false;
218 QDataStream ts(&f);
219 ts.device()->seek(startPos);
220 while (!ts.atEnd())
221 {
222 tmp = readLineFromDataStream(ts);
223 if (tmp.startsWith("%%Creator: "))
224 m_Creator = tmp.remove("%%Creator: ");
225 if (tmp.startsWith("%%Pages: "))
226 {
227 tmp = tmp.remove("%%Pages: ");
228 bool ok;
229 int pages = tmp.toInt( &ok );
230 if (ok)
231 m_imageInfoRecord.numberOfPages = pages;
232 }
233 if (tmp.startsWith("%%Trailer"))
234 m_inTrailer = true;
235 if (tmp.startsWith("%%BoundingBox:"))
236 {
237 found = true;
238 if (m_inTrailer)
239 m_BBoxInTrailer = true;
240 m_BBox = tmp.remove("%%BoundingBox:");
241 }
242 if (!found)
243 {
244 if (tmp.startsWith("%%BoundingBox"))
245 {
246 found = true;
247 if (m_inTrailer)
248 m_BBoxInTrailer = true;
249 m_BBox = tmp.remove("%%BoundingBox");
250 }
251 }
252 if (tmp.startsWith("%%Orientation:"))
253 {
254 if (tmp.contains("Landscape"))
255 m_isRotated = true;
256 }
257 if (tmp.startsWith("%%CyanPlate:"))
258 {
259 m_colorPlates.insert("Cyan", tmp.remove("%%CyanPlate: "));
260 m_isDCS1 = true;
261 }
262 if (tmp.startsWith("%%MagentaPlate:"))
263 {
264 m_colorPlates.insert("Magenta", tmp.remove("%%MagentaPlate: "));
265 m_isDCS1 = true;
266 }
267 if (tmp.startsWith("%%YellowPlate:"))
268 {
269 m_colorPlates.insert("Yellow", tmp.remove("%%YellowPlate: "));
270 m_isDCS1 = true;
271 }
272 if (tmp.startsWith("%%BlackPlate:"))
273 {
274 m_colorPlates.insert("Black", tmp.remove("%%BlackPlate: "));
275 m_isDCS1 = true;
276 }
277 if (tmp.startsWith("%%PlateFile: ("))
278 {
279 tmp = tmp.remove("%%PlateFile: (");
280 int endNam = tmp.indexOf(")");
281 QString plateNam = tmp.left(endNam);
282 tmp = tmp.remove(plateNam+")");
283 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
284 QString posStr, dummy, lenStr;
285 ts2 >> dummy >> posStr >> lenStr;
286 if (dummy == "EPS")
287 {
288 if (posStr.startsWith("#"))
289 {
290 posStr = posStr.remove(0, 1);
291 uint pos = posStr.toUInt();
292 uint len = lenStr.toUInt();
293 struct plateOffsets offs;
294 if (m_Creator.contains("Photoshop Version 9")) // This is very strange, it seems that there is a bug in PS 9 which writes weird entries
295 {
296 pos -= (191 + plateCount * 83);
297 len -= 83;
298 }
299 offs.pos = pos;
300 offs.len = len;
301 m_colorPlates2.insert(plateNam, offs);
302 m_isDCS2 = true;
303 plateCount++;
304 }
305 else
306 {
307 m_colorPlates.insert(plateNam, lenStr);
308 m_isDCS2 = true;
309 m_isDCS2multi = true;
310 }
311 }
312 }
313 if (tmp.startsWith("%%DocumentFonts:"))
314 {
315 tmp = tmp.remove("%%DocumentFonts:");
316 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
317 QString tmp2;
318 ts2 >> tmp2;
319 if (!tmp2.contains("(atend)"))
320 {
321 if (!tmp2.isEmpty())
322 m_FontListe.append(tmp2);
323 while (!ts.atEnd())
324 {
325 uint oldPos = ts.device()->pos();
326 tmp = readLineFromDataStream(ts);
327 if (!tmp.startsWith("%%+"))
328 {
329 ts.device()->seek(oldPos);
330 break;
331 }
332 tmp = tmp.remove(0,3);
333 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
334 QString tmp2;
335 ts2 >> tmp2;
336 if (!tmp2.isEmpty())
337 m_FontListe.append(tmp2);
338 }
339 }
340 else
341 isAtend = true;
342 }
343 if (tmp.startsWith("%%CMYKCustomColor"))
344 {
345 tmp = tmp.remove(0,18);
346 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
347 ts2 >> c >> m >> y >> k;
348 FarNam = ts2.readAll();
349 FarNam = FarNam.trimmed();
350 FarNam = FarNam.remove(0,1);
351 FarNam = FarNam.remove(FarNam.length()-1,1);
352 cc = ScColor(static_cast<int>(255 * c), static_cast<int>(255 * m), static_cast<int>(255 * y), static_cast<int>(255 * k));
353 cc.setSpotColor(true);
354 m_CustColors.insert(FarNam, cc);
355 while (!ts.atEnd())
356 {
357 uint oldPos = ts.device()->pos();
358 tmp = readLineFromDataStream(ts);
359 if (!tmp.startsWith("%%+"))
360 {
361 ts.device()->seek(oldPos);
362 break;
363 }
364 tmp = tmp.remove(0,3);
365 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
366 ts2 >> c >> m >> y >> k;
367 FarNam = ts2.readAll();
368 FarNam = FarNam.trimmed();
369 FarNam = FarNam.remove(0,1);
370 FarNam = FarNam.remove(FarNam.length()-1,1);
371 cc = ScColor(static_cast<int>(255 * c), static_cast<int>(255 * m), static_cast<int>(255 * y), static_cast<int>(255 * k));
372 cc.setSpotColor(true);
373 m_CustColors.insert(FarNam, cc);
374 }
375 }
376 if (tmp.startsWith("%%EndComments"))
377 {
378 while (!ts.atEnd())
379 {
380 tmp = readLineFromDataStream(ts);
381 if ((!tmp.isEmpty()) && (!tmp.startsWith("%")))
382 {
383 psFound = true;
384 break;
385 }
386 if (tmp.startsWith("%ImageData: "))
387 {
388 m_hasPhotoshopImageData = true;
389 tmp.remove("%ImageData: ");
390 ScTextStream ts2(&tmp, QIODevice::ReadOnly);
391 ts2 >> m_psXSize >> m_psYSize >> m_psDepth >> m_psMode >> m_psChannel >> m_psBlock >> m_psDataType >> m_psCommand;
392 m_psCommand = m_psCommand.remove(0,1);
393 m_psCommand = m_psCommand.remove(m_psCommand.length()-1,1);
394 }
395 if (tmp.startsWith("%BeginPhotoshop"))
396 {
397 QByteArray psdata;
398 while (!ts.atEnd())
399 {
400 tmp = readLineFromDataStream(ts);
401 if (tmp.startsWith("%EndPhotoshop"))
402 {
403 QDataStream strPhot( &psdata, QIODevice::ReadOnly);
404 strPhot.setByteOrder( QDataStream::BigEndian );
405 PSDHeader fakeHeader;
406 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
407 ts2 >> x >> y >> b >> h;
408 fakeHeader.width = qRound(b);
409 fakeHeader.height = qRound(h);
410 parseResourceData(strPhot, fakeHeader, psdata.size());
411 m_imageInfoRecord.valid = (m_imageInfoRecord.PDSpathData.size()) > 0;
412 if (!m_imageInfoRecord.PDSpathData.empty())
413 {
414 QTransform mm;
415 mm.scale(m_imageInfoRecord.xres / 72.0, m_imageInfoRecord.yres / 72.0);
416 QMap<QString, FPointArray>::Iterator it;
417 for (it = m_imageInfoRecord.PDSpathData.begin(); it != m_imageInfoRecord.PDSpathData.end(); ++it)
418 {
419 it.value().map(mm);
420 }
421 }
422 m_isPhotoshop = true;
423 break;
424 }
425 for (int a = 2; a < tmp.length(); a += 2)
426 {
427 bool ok;
428 ushort data = tmp.midRef(a, 2).toUShort(&ok, 16);
429 psdata.resize(psdata.size()+1);
430 psdata[psdata.size()-1] = data;
431 }
432 }
433 if ((m_doThumbnail) && ((m_hasThumbnail) || (!m_imageInfoRecord.exifInfo.thumbnail.isNull())))
434 return true;
435 }
436 if (tmp.startsWith("%%BeginICCProfile:"))
437 {
438 QByteArray psdata;
439 while (!ts.atEnd())
440 {
441 tmp = readLineFromDataStream(ts);
442 for (int a = 2; a < tmp.length(); a += 2)
443 {
444 bool ok;
445 ushort data = tmp.midRef(a, 2).toUShort(&ok, 16);
446 psdata.resize(psdata.size()+1);
447 psdata[psdata.size()-1] = data;
448 }
449 if (tmp.startsWith("%%EndICCProfile"))
450 {
451 ScColorMgmtEngine engine(ScCore->defaultEngine);
452 ScColorProfile prof = engine.openProfileFromMem(psdata);
453 if (prof)
454 {
455 if (prof.colorSpace() == ColorSpace_Rgb)
456 m_profileComponents = 3;
457 if (prof.colorSpace() == ColorSpace_Cmyk)
458 m_profileComponents = 4;
459 m_imageInfoRecord.profileName = prof.productDescription();
460 m_imageInfoRecord.isEmbedded = true;
461 m_embeddedProfile = psdata;
462 }
463 break;
464 }
465 }
466 }
467 if (psFound)
468 break;
469 }
470 }
471 if ((psFound) && (!isAtend))
472 break;
473 }
474 }
475 f.close();
476 return true;
477 }
478
loadPicture(const QString & fn,int page,int gsRes,bool thumbnail)479 bool ScImgDataLoader_PS::loadPicture(const QString& fn, int page, int gsRes, bool thumbnail)
480 {
481 double x = 0;
482 double y = 0;
483 double b = 0;
484 double h = 0;
485 bool found = false;
486 QFileInfo fi = QFileInfo(fn);
487 if (!fi.exists())
488 return false;
489 QString ext = fi.suffix().toLower();
490 if (ext.isEmpty())
491 ext = getImageType(fn);
492 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + QString("sc%1.png").arg(qMax(1, page)));
493 QString tmpFiles = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc%d.png");
494 QString picFile = QDir::toNativeSeparators(fn);
495 float xres = gsRes;
496 float yres = gsRes;
497
498 initialize();
499
500 m_imageInfoRecord.type = ImageTypeEPS;
501 m_imageInfoRecord.exifDataValid = false;
502 m_imageInfoRecord.numberOfPages = 1; // will be overwritten by parse()
503 m_doThumbnail = thumbnail;
504 m_colorPlates2.clear();
505 m_colorPlates.clear();
506 m_CustColors.clear();
507 m_CustColors.insert("Cyan", ScColor(255, 0, 0, 0));
508 m_CustColors.insert("Magenta", ScColor(0, 255, 0, 0));
509 m_CustColors.insert("Yellow", ScColor(0, 0, 255, 0));
510 m_CustColors.insert("Black", ScColor(0, 0, 0, 255));
511 found = parseData(fn);
512 if (m_FontListe.count() != 0)
513 {
514 scanForFonts(fn);
515 if (m_FontListe.count() != 0)
516 {
517 bool missing = false;
518 QString missingF = "";
519 for (int fo = 0; fo < m_FontListe.count(); fo++)
520 {
521 if (!PrefsManager::instance().appPrefs.fontPrefs.AvailFonts.contains(m_FontListe[fo]))
522 {
523 missing = true;
524 missingF += m_FontListe[fo]+"\n";
525 }
526 }
527 if (missing)
528 {
529 m_message = QObject::tr("The Font(s):\n%1 are not embedded or available for Scribus.\nThey might be replaced by \"Courier\", depending how your Ghostscript is configured.\nTherefore the image may be not correct").arg(missingF);
530 m_msgType = warningMsg;
531 }
532 }
533 }
534 if ((thumbnail) && (m_imageInfoRecord.exifDataValid) && (!m_imageInfoRecord.exifInfo.thumbnail.isNull()))
535 {
536 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
537 ts2 >> x >> y >> b >> h;
538 m_imageInfoRecord.exifInfo.width = qRound(b);
539 m_imageInfoRecord.exifInfo.height = qRound(h);
540 m_image = m_imageInfoRecord.exifInfo.thumbnail;
541 if ((m_isPhotoshop) && (m_hasPhotoshopImageData))
542 {
543 m_imageInfoRecord.exifInfo.width = m_psXSize;
544 m_imageInfoRecord.exifInfo.height = m_psYSize;
545 m_imageInfoRecord.type = ImageType7;
546 if (m_psMode == 4)
547 {
548 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
549 QRgb *s;
550 unsigned char cc, cm, cy, ck;
551 for (int yit = 0; yit < m_image.height(); ++yit)
552 {
553 s = (QRgb*)(m_image.scanLine( yit ));
554 for (int xit = 0; xit < m_image.width(); ++xit)
555 {
556 cc = 255 - qRed(*s);
557 cm = 255 - qGreen(*s);
558 cy = 255 - qBlue(*s);
559 ck = qMin(qMin(cc, cm), cy);
560 *s = qRgba(cc-ck,cm-ck,cy-ck,ck);
561 s++;
562 }
563 }
564 }
565 else
566 m_imageInfoRecord.colorspace = ColorSpaceRGB;
567 }
568 else
569 m_imageInfoRecord.colorspace = ColorSpaceRGB;
570 m_imageInfoRecord.actualPageNumber = page;
571 m_pixelFormat = Format_BGRA_8;
572 return true;
573 }
574 if (found)
575 {
576 if (m_isDCS1)
577 loadDCS1(fn, gsRes);
578 else if (m_isDCS2)
579 loadDCS2(fn, gsRes);
580 else if ((m_isPhotoshop) && (m_hasPhotoshopImageData))
581 loadPhotoshop(fn, gsRes);
582 else if ((!m_imageInfoRecord.isEmbedded) || ((m_imageInfoRecord.isEmbedded) && (m_profileComponents == 3)))
583 {
584 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
585 ts2 >> x >> y >> b >> h;
586 QStringList args;
587 xres = gsRes;
588 yres = gsRes;
589 if (extensionIndicatesEPS(ext))
590 {
591 if (!m_BBoxInTrailer)
592 args.append("-dEPSCrop");
593 }
594 args.append("-r"+QString::number(gsRes));
595 args.append("-sOutputFile="+tmpFiles);
596 args.append(picFile);
597 h = h * gsRes / 72.0;
598 int retg = callGS(args);
599 if (retg == 0)
600 {
601 m_image.load(tmpFile);
602 if ((extensionIndicatesEPS(ext) && m_BBoxInTrailer) || (m_isRotated))
603 {
604 int ex = qRound(x * gsRes / 72.0);
605 int ey = qRound(m_image.height() - h);
606 int ew = qRound((b - x) * gsRes / 72.0);
607 int eh = qRound(h - y * gsRes / 72.0);
608 m_image = m_image.copy(ex, ey, ew, eh);
609 }
610 if ((!ScCore->havePNGAlpha()) || (m_isRotated))
611 {
612 int wi = m_image.width();
613 int hi = m_image.height();
614 QRgb alphaFF = qRgba(255,255,255,255);
615 QRgb alpha00 = qRgba(255,255,255, 0);
616 QRgb *s;
617 for (int yi = 0; yi < hi; ++yi)
618 {
619 s = (QRgb*)(m_image.scanLine( yi ));
620 for (int xi = 0; xi < wi; ++xi)
621 {
622 if ((*s) == alphaFF)
623 (*s) &= alpha00;
624 s++;
625 }
626 }
627 }
628
629 QStringList files = QStringList("sc*.png");
630 files = QDir(ScPaths::tempFileDir()).entryList(files);
631 for (int i=0; i < files.count(); ++i)
632 QFile::remove(QDir::toNativeSeparators(ScPaths::tempFileDir() + files[i]));
633
634 if (extensionIndicatesEPS(ext))
635 {
636 m_imageInfoRecord.BBoxX = static_cast<int>(x);
637 m_imageInfoRecord.BBoxH = static_cast<int>(h);
638 }
639 else
640 {
641 m_imageInfoRecord.BBoxX = 0;
642 m_imageInfoRecord.BBoxH = m_image.height();
643 }
644 m_imageInfoRecord.xres = gsRes;
645 m_imageInfoRecord.yres = gsRes;
646 if ((m_imageInfoRecord.isEmbedded) && (m_profileComponents == 3))
647 m_imageInfoRecord.type = ImageType7;
648 m_imageInfoRecord.colorspace = ColorSpaceRGB;
649 m_image.setDotsPerMeterX ((int) (xres / 0.0254));
650 m_image.setDotsPerMeterY ((int) (yres / 0.0254));
651 m_pixelFormat = Format_BGRA_8;
652 }
653 }
654 else
655 {
656 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
657 ts2 >> x >> y >> b >> h;
658 h = h * gsRes / 72.0;
659 QStringList args;
660 xres = gsRes;
661 yres = gsRes;
662 if (extensionIndicatesEPS(ext))
663 args.append("-dEPSCrop");
664 args.append("-dGrayValues=256");
665 args.append("-r"+QString::number(gsRes));
666 args.append("-sOutputFile="+tmpFiles);
667 args.append(picFile);
668 // qDebug() << "scimgdataloader_ps:" << args;
669 int retg = callGS(args);
670 if (retg == 0)
671 {
672 m_image.load(tmpFile);
673 x = 0;
674 b = m_image.width() / gsRes * 72.0;
675 h = m_image.height() / gsRes * 72.0;
676 }
677 retg = callGS(args, "bitcmyk");
678 if (retg == 0)
679 {
680 m_image = QImage( qRound(b * gsRes / 72.0), qRound(h * gsRes / 72.0), QImage::Format_ARGB32 );
681 m_image.fill(qRgba(0, 0, 0, 0));
682 int w = qRound(b * gsRes / 72.0);
683 int w2 = 4*w;
684 int h2 = qRound(h * gsRes / 72.0);
685 uint *p;
686 int cyan, magenta, yellow, black;
687 QByteArray imgc(w2, ' ');
688 QFile f(tmpFile);
689 if (f.open(QIODevice::ReadOnly))
690 {
691 for (int y=0; y < h2; ++y )
692 {
693 p = (uint *)m_image.scanLine( y );
694 f.read(imgc.data(), w2);
695 for (int x=0; x < w2; x += 4 )
696 {
697 cyan = uchar(imgc[x]);
698 magenta = uchar(imgc[x + 1]);
699 yellow = uchar(imgc[x + 2]);
700 black = uchar(imgc[x + 3]);
701 *p = qRgba(cyan, magenta, yellow, black);
702 p++;
703 }
704 }
705 f.close();
706 }
707
708 QStringList files = QStringList("sc*.png");
709 files = QDir(ScPaths::tempFileDir()).entryList(files);
710 for (int i=0; i < files.count(); ++i)
711 QFile::remove(QDir::toNativeSeparators(ScPaths::tempFileDir() + files[i]));
712
713 if (extensionIndicatesEPS(ext))
714 {
715 m_imageInfoRecord.BBoxX = static_cast<int>(x);
716 m_imageInfoRecord.BBoxH = static_cast<int>(h);
717 }
718 else
719 {
720 m_imageInfoRecord.BBoxX = 0;
721 m_imageInfoRecord.BBoxH = m_image.height();
722 }
723 m_imageInfoRecord.xres = gsRes;
724 m_imageInfoRecord.yres = gsRes;
725 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
726 m_imageInfoRecord.type = ImageType7;
727 m_image.setDotsPerMeterX ((int) (xres / 0.0254));
728 m_image.setDotsPerMeterY ((int) (yres / 0.0254));
729 m_pixelFormat = Format_YMCK_8;
730 }
731 else
732 {
733 qDebug() << "Ghostscript returned result" << retg;
734 }
735 }
736 m_imageInfoRecord.actualPageNumber = page;
737 return true;
738 }
739 return false;
740 }
741
loadPhotoshop(const QString & fn,int gsRes)742 void ScImgDataLoader_PS::loadPhotoshop(const QString& fn, int gsRes)
743 {
744 if ((m_psDataType >= 1) && (m_psDataType <= 6) && ((m_psMode == 3) || (m_psMode == 4)))
745 {
746 loadPhotoshopBinary(fn);
747 return;
748 }
749 QStringList args;
750 QFileInfo fi = QFileInfo(fn);
751 QString ext = fi.suffix().toLower();
752 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc1.png");
753 int retg;
754 int GsVersion;
755 getNumericGSVersion(GsVersion);
756 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
757 double x, y, b, h;
758 ts2 >> x >> y >> b >> h;
759 h = h * gsRes / 72.0;
760 if (extensionIndicatesEPS(ext))
761 args.append("-dEPSCrop");
762 if (m_psMode == 4)
763 args.append("-dGrayValues=256");
764 if (GsVersion >= 853)
765 args.append("-dNOPSICC"); // prevent GS from applying an embedded ICC profile as it will be applied later on in ScImage.
766 args.append("-r"+QString::number(gsRes));
767 args.append("-sOutputFile=" + tmpFile);
768 args.append(QDir::toNativeSeparators(fn));
769 if (m_psMode == 4)
770 retg = callGS(args, "bitcmyk");
771 else
772 retg = callGS(args);
773 if (retg == 0)
774 {
775 if (m_psMode == 4)
776 {
777 m_image = QImage( qRound(b * gsRes / 72.0), qRound(h * gsRes / 72.0), QImage::Format_ARGB32 );
778 m_image.fill(qRgba(0, 0, 0, 0));
779 int w = qRound(b * gsRes / 72.0);
780 int w2 = 4*w;
781 int h2 = qRound(h * gsRes / 72.0);
782 uint *p;
783 int cyan, magenta, yellow, black;
784 QByteArray imgc(w2, ' ');
785 QFile f(tmpFile);
786 if (f.open(QIODevice::ReadOnly))
787 {
788 for (int y=0; y < h2; ++y )
789 {
790 p = (uint *)m_image.scanLine( y );
791 f.read(imgc.data(), w2);
792 for (int x=0; x < w2; x += 4 )
793 {
794 cyan = uchar(imgc[x]);
795 magenta = uchar(imgc[x + 1]);
796 yellow = uchar(imgc[x + 2]);
797 black = uchar(imgc[x + 3]);
798 *p = qRgba(cyan, magenta, yellow, black);
799 p++;
800 }
801 }
802 f.close();
803 }
804 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
805 m_imageInfoRecord.type = ImageType7;
806 m_pixelFormat = Format_YMCK_8;
807 }
808 else
809 {
810 m_image.load(tmpFile);
811 if (!ScCore->havePNGAlpha())
812 {
813 int wi = m_image.width();
814 int hi = m_image.height();
815 QRgb alphaFF = qRgba(255,255,255,255);
816 QRgb alpha00 = qRgba(255,255,255, 0);
817 QRgb *s;
818 for (int yi = 0; yi < hi; ++yi)
819 {
820 s = (QRgb*)(m_image.scanLine( yi ));
821 for (int xi = 0; xi < wi; ++xi)
822 {
823 if ((*s) == alphaFF)
824 (*s) &= alpha00;
825 s++;
826 }
827 }
828 }
829 m_imageInfoRecord.type = ImageType7;
830 m_imageInfoRecord.colorspace = ColorSpaceRGB;
831 m_pixelFormat = Format_BGRA_8;
832 }
833
834 QFile::remove(tmpFile);
835
836 if (extensionIndicatesEPS(ext))
837 {
838 m_imageInfoRecord.BBoxX = static_cast<int>(x);
839 m_imageInfoRecord.BBoxH = static_cast<int>(h);
840 }
841 else
842 {
843 m_imageInfoRecord.BBoxX = 0;
844 m_imageInfoRecord.BBoxH = m_image.height();
845 }
846 m_image.setDotsPerMeterX ((int) (m_imageInfoRecord.xres / 0.0254));
847 m_image.setDotsPerMeterY ((int) (m_imageInfoRecord.yres / 0.0254));
848 }
849 else
850 {
851 qDebug() << "Ghostscript returned result" << retg;
852 }
853 }
854
decodeA85(QByteArray & psdata,const QString & tmp)855 void ScImgDataLoader_PS::decodeA85(QByteArray &psdata, const QString& tmp)
856 {
857 uchar byte;
858 ushort data;
859 unsigned long sum = 0;
860 int quintet = 0;
861 for (int c = 0; c < tmp.length(); c++)
862 {
863 byte = QChar(tmp.at(c)).cell();
864 if (byte >= '!' && byte <= 'u')
865 {
866 sum = sum * 85 + ((unsigned long)byte - '!');
867 quintet++;
868 if (quintet == 5)
869 {
870 psdata.resize(psdata.size()+4);
871 data = sum >> 24;
872 psdata[psdata.size()-4] = data;
873 data = (sum >> 16) & 0xFF;
874 psdata[psdata.size()-3] = data;
875 data = (sum >> 8) & 0xFF;
876 psdata[psdata.size()-2] = data;
877 data = sum & 0xFF;
878 psdata[psdata.size()-1] = data;
879 quintet = 0;
880 sum = 0;
881 }
882 }
883 else if (byte == 'z')
884 {
885 psdata.resize(psdata.size()+4);
886 psdata[psdata.size()-4] = 0;
887 psdata[psdata.size()-3] = 0;
888 psdata[psdata.size()-2] = 0;
889 psdata[psdata.size()-1] = 0;
890 }
891 else if (byte == '~')
892 {
893 if (quintet)
894 {
895 int i;
896 for (i = 0; i < 5 - quintet; i++)
897 sum *= 85;
898 if (quintet > 1)
899 sum += (0xFFFFFF >> ((quintet - 2) * 8));
900 for (i = 0; i < quintet - 1; i++)
901 {
902 data = (sum >> (24 - 8 * i)) & 0xFF;
903 psdata.resize(psdata.size()+1);
904 psdata[psdata.size()-1] = data;
905 }
906 }
907 break;
908 }
909 }
910 }
911
912 typedef struct my_error_mgr
913 {
914 struct jpeg_error_mgr pub; /* "public" fields */
915 jmp_buf setjmp_buffer; /* for return to caller */
916 } *my_error_ptr;
917
my_error_exit(j_common_ptr cinfo)918 static void my_error_exit (j_common_ptr cinfo)
919 {
920 my_error_ptr myerr = (my_error_ptr) cinfo->err;
921 (*cinfo->err->output_message) (cinfo);
922 longjmp (myerr->setjmp_buffer, 1);
923 }
924
loadPSjpeg(const QString & fn)925 bool ScImgDataLoader_PS::loadPSjpeg(const QString& fn)
926 {
927 if (!QFile::exists(fn))
928 return false;
929 struct jpeg_decompress_struct cinfo;
930 struct my_error_mgr jerr;
931 FILE *infile;
932 cinfo.err = jpeg_std_error (&jerr.pub);
933 jerr.pub.error_exit = my_error_exit;
934 infile = nullptr;
935 if (setjmp (jerr.setjmp_buffer))
936 {
937 jpeg_destroy_decompress (&cinfo);
938 if (infile)
939 fclose (infile);
940 return false;
941 }
942 jpeg_create_decompress (&cinfo);
943 #if defined(Q_OS_WIN32)
944 if ((infile = _wfopen((const wchar_t*) fn.utf16(), L"rb")) == nullptr)
945 return false;
946 #else
947 if ((infile = fopen (fn.toLocal8Bit(), "rb")) == nullptr)
948 return false;
949 #endif
950 jpeg_stdio_src(&cinfo, infile);
951 jpeg_read_header(&cinfo, true);
952 jpeg_start_decompress(&cinfo);
953 if ( cinfo.output_components == 3 || cinfo.output_components == 4)
954 m_image = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_ARGB32 );
955 else if ( cinfo.output_components == 1 )
956 {
957 m_image = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8 );
958 m_image.setColorCount(256);
959 for (int i=0; i<256; i++)
960 m_image.setColor(i, qRgb(i,i,i));
961 }
962 if (!m_image.isNull())
963 {
964 uchar* data = m_image.bits();
965 int bpl = m_image.bytesPerLine();
966 while (cinfo.output_scanline < cinfo.output_height)
967 {
968 uchar *d = data + cinfo.output_scanline * bpl;
969 (void) jpeg_read_scanlines(&cinfo, &d, 1);
970 }
971 if ( cinfo.output_components == 3 )
972 {
973 uchar *in;
974 QRgb *out;
975 for (uint j=0; j<cinfo.output_height; j++)
976 {
977 in = m_image.scanLine(j) + cinfo.output_width * 3;
978 out = (QRgb*) m_image.scanLine(j);
979 for (uint i=cinfo.output_width; i--; )
980 {
981 in -= 3;
982 out[i] = qRgb(in[0], in[1], in[2]);
983 }
984 }
985 m_pixelFormat = Format_BGRA_8;
986 }
987 if ( cinfo.output_components == 4 )
988 {
989 QRgb *ptr;
990 unsigned char c, m, y ,k;
991 unsigned char *p;
992 for (int i = 0; i < m_image.height(); i++)
993 {
994 ptr = (QRgb*) m_image.scanLine(i);
995 if ((cinfo.jpeg_color_space == JCS_YCCK) || ((cinfo.jpeg_color_space == JCS_CMYK) && (cinfo.saw_Adobe_marker)))
996 {
997 for (int j = 0; j < m_image.width(); j++)
998 {
999 p = (unsigned char *) ptr;
1000 c = p[0];
1001 m = p[1];
1002 y = p[2];
1003 k = p[3];
1004 *ptr = qRgba(c, m, y, k);
1005 ptr++;
1006 }
1007 }
1008 else
1009 {
1010 for (int j = 0; j < m_image.width(); j++)
1011 {
1012 p = (unsigned char *) ptr;
1013 c = p[0];
1014 m = p[1];
1015 y = p[2];
1016 k = p[3];
1017 *ptr = qRgba(y, m, c, k);
1018 ptr++;
1019 }
1020 }
1021 }
1022 m_pixelFormat = Format_YMCK_8;
1023 }
1024 if ( cinfo.output_components == 1 )
1025 {
1026 QImage tmpImg = m_image.convertToFormat(QImage::Format_ARGB32);
1027 m_image = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_ARGB32 );
1028 QRgb *s;
1029 QRgb *d;
1030 for (int yi=0; yi < tmpImg.height(); ++yi)
1031 {
1032 s = (QRgb*)(tmpImg.scanLine( yi ));
1033 d = (QRgb*)(m_image.scanLine( yi ));
1034 for (int xi=0; xi < tmpImg.width(); ++xi)
1035 {
1036 (*d) = (*s);
1037 s++;
1038 d++;
1039 }
1040 }
1041 m_pixelFormat = Format_BGRA_8;
1042 }
1043 }
1044 (void) jpeg_finish_decompress(&cinfo);
1045 fclose (infile);
1046 jpeg_destroy_decompress (&cinfo);
1047 return (!m_image.isNull());
1048 }
1049
loadPSjpeg(const QString & fn,QImage & tmpImg)1050 bool ScImgDataLoader_PS::loadPSjpeg(const QString& fn, QImage &tmpImg)
1051 {
1052 if (!QFile::exists(fn))
1053 return false;
1054 struct jpeg_decompress_struct cinfo;
1055 struct my_error_mgr jerr;
1056 FILE *infile;
1057 cinfo.err = jpeg_std_error (&jerr.pub);
1058 jerr.pub.error_exit = my_error_exit;
1059 infile = nullptr;
1060 if (setjmp (jerr.setjmp_buffer))
1061 {
1062 jpeg_destroy_decompress (&cinfo);
1063 if (infile)
1064 fclose (infile);
1065 return false;
1066 }
1067 jpeg_create_decompress (&cinfo);
1068 #if defined(Q_OS_WIN32)
1069 if ((infile = _wfopen((const wchar_t*) fn.utf16(), L"rb")) == nullptr)
1070 return false;
1071 #else
1072 if ((infile = fopen (fn.toLocal8Bit(), "rb")) == nullptr)
1073 return false;
1074 #endif
1075 jpeg_stdio_src(&cinfo, infile);
1076 jpeg_read_header(&cinfo, true);
1077 jpeg_start_decompress(&cinfo);
1078 if ( cinfo.output_components == 3 || cinfo.output_components == 4)
1079 tmpImg = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_ARGB32 );
1080 else if ( cinfo.output_components == 1 )
1081 {
1082 tmpImg = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_Indexed8 );
1083 m_image.setColorCount(256);
1084 for (int i=0; i<256; i++)
1085 tmpImg.setColor(i, qRgb(i,i,i));
1086 m_pixelFormat = Format_GRAY_8;
1087 }
1088 if (!tmpImg.isNull())
1089 {
1090 uchar* data = tmpImg.bits();
1091 int bpl = tmpImg.bytesPerLine();
1092 while (cinfo.output_scanline < cinfo.output_height)
1093 {
1094 uchar *d = data + cinfo.output_scanline * bpl;
1095 (void) jpeg_read_scanlines(&cinfo, &d, 1);
1096 }
1097 if ( cinfo.output_components == 3 )
1098 {
1099 uchar *in;
1100 QRgb *out;
1101 for (uint j=0; j<cinfo.output_height; j++)
1102 {
1103 in = tmpImg.scanLine(j) + cinfo.output_width * 3;
1104 out = (QRgb*) tmpImg.scanLine(j);
1105 for (uint i=cinfo.output_width; i--; )
1106 {
1107 in -= 3;
1108 out[i] = qRgb(in[0], in[1], in[2]);
1109 }
1110 }
1111 m_pixelFormat = Format_BGRA_8;
1112 }
1113 if ( cinfo.output_components == 4 )
1114 {
1115 QRgb *ptr;
1116 unsigned char c, m, y ,k;
1117 unsigned char *p;
1118 for (int i = 0; i < tmpImg.height(); i++)
1119 {
1120 ptr = (QRgb*) tmpImg.scanLine(i);
1121 if ((cinfo.jpeg_color_space == JCS_YCCK) || ((cinfo.jpeg_color_space == JCS_CMYK) && (cinfo.saw_Adobe_marker)))
1122 {
1123 for (int j = 0; j < tmpImg.width(); j++)
1124 {
1125 p = (unsigned char *) ptr;
1126 c = p[0];
1127 m = p[1];
1128 y = p[2];
1129 k = p[3];
1130 *ptr = qRgba(c, m, y, k);
1131 ptr++;
1132 }
1133 }
1134 else
1135 {
1136 for (int j = 0; j < tmpImg.width(); j++)
1137 {
1138 p = (unsigned char *) ptr;
1139 c = p[0];
1140 m = p[1];
1141 y = p[2];
1142 k = p[3];
1143 *ptr = qRgba(y, m, c, k);
1144 ptr++;
1145 }
1146 }
1147 }
1148 m_pixelFormat = Format_YMCK_8;
1149 }
1150 if ( cinfo.output_components == 1 )
1151 {
1152 QImage tmpImg2 = tmpImg.convertToFormat(QImage::Format_ARGB32);
1153 tmpImg = QImage( cinfo.output_width, cinfo.output_height, QImage::Format_ARGB32 );
1154 QRgb *s;
1155 QRgb *d;
1156 for (int yi=0; yi < tmpImg2.height(); ++yi)
1157 {
1158 s = (QRgb*)(tmpImg2.scanLine( yi ));
1159 d = (QRgb*)(tmpImg.scanLine( yi ));
1160 for (int xi=0; xi < tmpImg2.width(); ++xi)
1161 {
1162 (*d) = (*s);
1163 s++;
1164 d++;
1165 }
1166 }
1167 }
1168 }
1169 (void) jpeg_finish_decompress(&cinfo);
1170 fclose (infile);
1171 jpeg_destroy_decompress (&cinfo);
1172 return (!tmpImg.isNull());
1173 }
1174
loadPhotoshopBinary(const QString & fn)1175 void ScImgDataLoader_PS::loadPhotoshopBinary(const QString& fn)
1176 {
1177 double x, y, b, h;
1178 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
1179 ts2 >> x >> y >> b >> h;
1180 QString tmpFile(QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc1.jpg"));
1181 QFile f2(tmpFile);
1182 QString tmp;
1183 m_image = QImage(m_psXSize, m_psYSize, QImage::Format_ARGB32);
1184 m_image.fill(qRgba(0, 0, 0, 0));
1185 m_imageInfoRecord.xres = qRound(m_psXSize / b * 72.0);
1186 m_imageInfoRecord.yres = qRound(m_psYSize / h * 72.0);
1187 QByteArray psdata;
1188 QFile f(fn);
1189 int yCount = 0;
1190 if (!f.open(QIODevice::ReadOnly))
1191 {
1192 qDebug()<<"Failed to open QFile f in ScImgDataLoader_PS::loadPhotoshopBinary";
1193 return;
1194 }
1195 if (m_psDataType > 2)
1196 {
1197 if (!f2.open(QIODevice::WriteOnly))
1198 {
1199 qDebug()<<"Failed to open QFile f2 in ScImgDataLoader_PS::loadPhotoshopBinary";
1200 return;
1201 }
1202 }
1203 QDataStream ts(&f);
1204 while (!ts.atEnd())
1205 {
1206 tmp = readLineFromDataStream(ts);
1207 if (tmp == m_psCommand)
1208 {
1209 if (m_psDataType == 1)
1210 {
1211 QRgb *p;
1212 uchar cc, cm, cy, ck;
1213 for (int yh = 0; yh < m_image.height(); ++yh )
1214 {
1215 if (m_psMode == 4)
1216 psdata.resize(m_psXSize * (4 + m_psChannel));
1217 else
1218 psdata.resize(m_psXSize * (3 + m_psChannel));
1219 f.read(psdata.data(), psdata.size());
1220 p = (QRgb *)m_image.scanLine( yh );
1221 for (int xh = 0; xh < m_image.width(); ++xh )
1222 {
1223 cc = psdata[xh];
1224 cm = psdata[m_psXSize+xh];
1225 cy = psdata[m_psXSize*2+xh];
1226 ck = psdata[m_psXSize*3+xh];
1227 if (m_psMode == 4)
1228 *p = qRgba(cc, cm, cy, ck);
1229 else
1230 *p = qRgba(cc, cm, cy, 255);
1231 p++;
1232 }
1233 }
1234 }
1235 else if (m_psDataType > 1)
1236 {
1237 while (!ts.atEnd())
1238 {
1239 tmp = readLineFromDataStream(ts);
1240 if ((tmp.isEmpty()) || (tmp.startsWith("%%EndBinary")))
1241 break;
1242 if (m_psDataType == 2)
1243 {
1244 for (int a = 0; a < tmp.length(); a += 2)
1245 {
1246 bool ok;
1247 ushort data = tmp.midRef(a, 2).toUShort(&ok, 16);
1248 psdata.resize(psdata.size()+1);
1249 psdata[psdata.size()-1] = data;
1250 }
1251 }
1252 else
1253 {
1254 decodeA85(psdata, tmp);
1255 f2.write(psdata.data(), psdata.size());
1256 psdata.resize(0);
1257 }
1258 }
1259 if (m_psDataType > 2)
1260 {
1261 f2.close();
1262 loadPSjpeg(tmpFile);
1263 QFile::remove(tmpFile);
1264 }
1265 else
1266 {
1267 QRgb *p;
1268 uchar cc, cm, cy, ck;
1269 for (int yh = 0; yh < m_image.height(); ++yh )
1270 {
1271 p = (QRgb *)m_image.scanLine( yh );
1272 for (int xh = 0; xh < m_image.width(); ++xh )
1273 {
1274 cc = psdata[yCount+xh];
1275 cm = psdata[yCount+m_psXSize+xh];
1276 cy = psdata[yCount+m_psXSize*2+xh];
1277 if (m_psMode == 4)
1278 {
1279 ck = psdata[yCount+m_psXSize*3+xh];
1280 *p = qRgba(cc, cm, cy, ck);
1281 }
1282 else
1283 *p = qRgba(cc, cm, cy, 255);
1284 p++;
1285 }
1286 if (m_psMode == 4)
1287 yCount += m_psXSize * (4 + m_psChannel);
1288 else
1289 yCount += m_psXSize * (3 + m_psChannel);
1290 }
1291 }
1292 }
1293 if (m_psMode == 4)
1294 {
1295 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
1296 m_pixelFormat = Format_YMCK_8;
1297 }
1298 else
1299 {
1300 m_imageInfoRecord.colorspace = ColorSpaceRGB;
1301 m_pixelFormat = Format_BGRA_8;
1302 }
1303 m_imageInfoRecord.type = ImageType7;
1304 m_imageInfoRecord.BBoxX = 0;
1305 m_imageInfoRecord.BBoxH = m_image.height();
1306 m_image.setDotsPerMeterX ((int) (m_imageInfoRecord.xres / 0.0254));
1307 m_image.setDotsPerMeterY ((int) (m_imageInfoRecord.yres / 0.0254));
1308 f.close();
1309 return;
1310 }
1311 }
1312 f.close();
1313 }
1314
loadPhotoshopBinary(const QString & fn,QImage & tmpImg)1315 void ScImgDataLoader_PS::loadPhotoshopBinary(const QString& fn, QImage &tmpImg)
1316 {
1317 double x, y, b, h;
1318 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
1319 ts2 >> x >> y >> b >> h;
1320 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc1.jpg");
1321 QFile f2(tmpFile);
1322 QString tmp;
1323 tmpImg = QImage(m_psXSize, m_psYSize, QImage::Format_ARGB32);
1324 tmpImg.fill(qRgba(0, 0, 0, 0));
1325 QByteArray psdata;
1326 QFile f(fn);
1327 int yCount = 0;
1328 if (f.open(QIODevice::ReadOnly))
1329 {
1330 if (m_psDataType > 2)
1331 {
1332 f2.open(QIODevice::WriteOnly);
1333 }
1334 QDataStream ts(&f);
1335 while (!ts.atEnd())
1336 {
1337 tmp = readLineFromDataStream(ts);
1338 if (tmp == m_psCommand)
1339 {
1340 if (m_psDataType == 1)
1341 {
1342 QRgb *p;
1343 uchar cc, cm, cy, ck;
1344 for (int yh = 0; yh < tmpImg.height(); ++yh )
1345 {
1346 if (m_psMode == 4)
1347 psdata.resize(m_psXSize * (4 + m_psChannel));
1348 else
1349 psdata.resize(m_psXSize * (3 + m_psChannel));
1350 f.read(psdata.data(), psdata.size());
1351 p = (QRgb *)tmpImg.scanLine( yh );
1352 for (int xh = 0; xh < tmpImg.width(); ++xh )
1353 {
1354 cc = psdata[xh];
1355 cm = psdata[m_psXSize+xh];
1356 cy = psdata[m_psXSize*2+xh];
1357 if (m_psMode == 4)
1358 {
1359 ck = psdata[m_psXSize*3+xh];
1360 *p = qRgba(cc, cm, cy, ck);
1361 }
1362 else
1363 *p = qRgba(cc, cm, cy, 255);
1364 p++;
1365 }
1366 }
1367 }
1368 else if (m_psDataType > 1)
1369 {
1370 while (!ts.atEnd())
1371 {
1372 tmp = readLineFromDataStream(ts);
1373 if ((tmp.isEmpty()) || (tmp.startsWith("%%EndBinary")))
1374 break;
1375 if (m_psDataType == 2)
1376 {
1377 for (int a = 0; a < tmp.length(); a += 2)
1378 {
1379 bool ok;
1380 ushort data = tmp.midRef(a, 2).toUShort(&ok, 16);
1381 psdata.resize(psdata.size()+1);
1382 psdata[psdata.size()-1] = data;
1383 }
1384 }
1385 else
1386 {
1387 decodeA85(psdata, tmp);
1388 f2.write(psdata.data(), psdata.size());
1389 psdata.resize(0);
1390 }
1391 }
1392 if (m_psDataType > 2)
1393 {
1394 f2.close();
1395 loadPSjpeg(tmpFile, tmpImg);
1396 QFile::remove(tmpFile);
1397 }
1398 else
1399 {
1400 QRgb *p;
1401 uchar cc, cm, cy, ck;
1402 for (int yh = 0; yh < tmpImg.height(); ++yh )
1403 {
1404 p = (QRgb *)tmpImg.scanLine( yh );
1405 for (int xh = 0; xh < tmpImg.width(); ++xh )
1406 {
1407 cc = psdata[yCount+xh];
1408 cm = psdata[yCount+m_psXSize+xh];
1409 cy = psdata[yCount+m_psXSize*2+xh];
1410 if (m_psMode == 4)
1411 {
1412 ck = psdata[yCount+m_psXSize*3+xh];
1413 *p = qRgba(cc, cm, cy, ck);
1414 }
1415 else
1416 *p = qRgba(cc, cm, cy, 255);
1417 p++;
1418 }
1419 if (m_psMode == 4)
1420 yCount += m_psXSize * (4 + m_psChannel);
1421 else
1422 yCount += m_psXSize * (3 + m_psChannel);
1423 }
1424 }
1425 }
1426 f.close();
1427 return;
1428 }
1429 }
1430 f.close();
1431 }
1432 }
1433
loadDCS2(const QString & fn,int gsRes)1434 void ScImgDataLoader_PS::loadDCS2(const QString& fn, int gsRes)
1435 {
1436 QStringList args;
1437 double x, y, b, h;
1438 QFileInfo fi(fn);
1439 QString ext = fi.suffix().toLower();
1440 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc1.png");
1441 QString tmpFile2 = QDir::toNativeSeparators(ScPaths::tempFileDir() + "tmp.eps");
1442 QString baseFile = fi.absolutePath();
1443 QString picFile = QDir::toNativeSeparators(fn);
1444 float xres = gsRes;
1445 float yres = gsRes;
1446 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
1447 ts2 >> x >> y >> b >> h;
1448 xres = gsRes;
1449 yres = gsRes;
1450 if ((m_isPhotoshop) && (m_hasPhotoshopImageData))
1451 {
1452 m_image = QImage(m_psXSize, m_psYSize, QImage::Format_ARGB32);
1453 xres = m_psXSize / b * 72.0;
1454 yres = m_psYSize / h * 72.0;
1455 }
1456 else
1457 m_image = QImage( qRound(b * gsRes / 72.0), qRound(h * gsRes / 72.0), QImage::Format_ARGB32 );
1458 m_image.fill(qRgba(0, 0, 0, 0));
1459 if (!m_isDCS2multi)
1460 {
1461 for (QMap<QString, plateOffsets>::Iterator it = m_colorPlates2.begin(); it != m_colorPlates2.end(); ++it)
1462 {
1463 QByteArray imgc(it.value().len, ' ');
1464 QFile f(picFile);
1465 if (f.open(QIODevice::ReadOnly))
1466 {
1467 f.seek(it.value().pos);
1468 f.read(imgc.data(), it.value().len);
1469 }
1470 f.close();
1471 QFile f2(tmpFile2);
1472 if (f2.open(QIODevice::WriteOnly))
1473 f2.write(imgc.data(), it.value().len);
1474 f2.close();
1475 imgc.resize(0);
1476 if ((m_isPhotoshop) && (m_hasPhotoshopImageData))
1477 {
1478 QImage tmpImg;
1479 loadPhotoshopBinary(tmpFile2, tmpImg);
1480 blendImages(tmpImg, m_CustColors[it.key()]);
1481 }
1482 else
1483 {
1484 args.append("-dEPSCrop");
1485 args.append("-r"+QString::number(gsRes));
1486 args.append("-sOutputFile="+tmpFile);
1487 args.append(tmpFile2);
1488 int retg = callGS(args);
1489 if (retg == 0)
1490 {
1491 QImage tmpImg;
1492 tmpImg.load(tmpFile);
1493 blendImages(tmpImg, m_CustColors[it.key()]);
1494 QFile::remove(tmpFile);
1495 }
1496 }
1497 QFile::remove(tmpFile2);
1498 }
1499 }
1500 else
1501 {
1502 for (QMap<QString, QString>::Iterator it = m_colorPlates.begin(); it != m_colorPlates.end(); ++it)
1503 {
1504 tmpFile2 = QDir::toNativeSeparators(baseFile+"/"+it.value());
1505 if ((m_isPhotoshop) && (m_hasPhotoshopImageData))
1506 {
1507 QImage tmpImg;
1508 loadPhotoshopBinary(tmpFile2, tmpImg);
1509 blendImages(tmpImg, m_CustColors[it.key()]);
1510 }
1511 else
1512 {
1513 args.append("-dEPSCrop");
1514 args.append("-r"+QString::number(gsRes));
1515 args.append("-sOutputFile="+tmpFile);
1516 args.append(tmpFile2);
1517 int retg = callGS(args);
1518 if (retg == 0)
1519 {
1520 QImage tmpImg;
1521 tmpImg.load(tmpFile);
1522 blendImages(tmpImg, m_CustColors[it.key()]);
1523 QFile::remove(tmpFile);
1524 }
1525 args.clear();
1526 }
1527 }
1528 }
1529 if (extensionIndicatesEPS(ext))
1530 {
1531 m_imageInfoRecord.BBoxX = static_cast<int>(x);
1532 m_imageInfoRecord.BBoxH = static_cast<int>(h);
1533 }
1534 else
1535 {
1536 m_imageInfoRecord.BBoxX = 0;
1537 m_imageInfoRecord.BBoxH = m_image.height();
1538 }
1539 m_imageInfoRecord.xres = qRound(xres);
1540 m_imageInfoRecord.yres = qRound(yres);
1541 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
1542 m_imageInfoRecord.type = ImageType7;
1543 m_image.setDotsPerMeterX ((int) (xres / 0.0254));
1544 m_image.setDotsPerMeterY ((int) (yres / 0.0254));
1545 m_pixelFormat = Format_YMCK_8;
1546 }
1547
loadDCS1(const QString & fn,int gsRes)1548 void ScImgDataLoader_PS::loadDCS1(const QString& fn, int gsRes)
1549 {
1550 QStringList args;
1551 double x, y, b, h;
1552 QFileInfo fi = QFileInfo(fn);
1553 QString ext = fi.suffix().toLower();
1554 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc1.png");
1555 QString baseFile = fi.absolutePath();
1556 QString picFile;
1557 float xres = gsRes;
1558 float yres = gsRes;
1559 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
1560 ts2 >> x >> y >> b >> h;
1561 xres = gsRes;
1562 yres = gsRes;
1563 m_image = QImage( qRound(b * gsRes / 72.0), qRound(h * gsRes / 72.0), QImage::Format_ARGB32 );
1564 m_image.fill(qRgba(0, 0, 0, 0));
1565 bool isEncapPS=extensionIndicatesEPS(ext);
1566 if (isEncapPS)
1567 args.append("-dEPSCrop");
1568 args.append("-r"+QString::number(gsRes));
1569 args.append("-sOutputFile="+tmpFile);
1570 picFile = QDir::toNativeSeparators(baseFile+"/"+m_colorPlates["Cyan"]);
1571 args.append(picFile);
1572 int retg = callGS(args);
1573 if (retg == 0)
1574 {
1575 QImage tmpImg;
1576 tmpImg.load(tmpFile);
1577 blendImages(tmpImg, ScColor(255, 0, 0, 0));
1578 QFile::remove(tmpFile);
1579 }
1580 args.clear();
1581
1582 if (isEncapPS)
1583 args.append("-dEPSCrop");
1584 args.append("-r"+QString::number(gsRes));
1585 args.append("-sOutputFile="+tmpFile);
1586 picFile = QDir::toNativeSeparators(baseFile+"/"+m_colorPlates["Magenta"]);
1587 args.append(picFile);
1588 retg = callGS(args);
1589 if (retg == 0)
1590 {
1591 QImage tmpImg;
1592 tmpImg.load(tmpFile);
1593 blendImages(tmpImg, ScColor(0, 255, 0, 0));
1594 QFile::remove(tmpFile);
1595 }
1596 args.clear();
1597
1598 if (isEncapPS)
1599 args.append("-dEPSCrop");
1600 args.append("-r"+QString::number(gsRes));
1601 args.append("-sOutputFile="+tmpFile);
1602 picFile = QDir::toNativeSeparators(baseFile+"/"+m_colorPlates["Yellow"]);
1603 args.append(picFile);
1604 retg = callGS(args);
1605 if (retg == 0)
1606 {
1607 QImage tmpImg;
1608 tmpImg.load(tmpFile);
1609 blendImages(tmpImg, ScColor(0, 0, 255, 0));
1610 QFile::remove(tmpFile);
1611 }
1612 args.clear();
1613
1614 if (isEncapPS)
1615 args.append("-dEPSCrop");
1616 args.append("-r"+QString::number(gsRes));
1617 args.append("-sOutputFile="+tmpFile);
1618 picFile = QDir::toNativeSeparators(baseFile+"/"+m_colorPlates["Black"]);
1619 args.append(picFile);
1620 retg = callGS(args);
1621 if (retg == 0)
1622 {
1623 QImage tmpImg;
1624 tmpImg.load(tmpFile);
1625 blendImages(tmpImg, ScColor(0, 0, 0, 255));
1626 QFile::remove(tmpFile);
1627 }
1628 args.clear();
1629
1630 if (isEncapPS)
1631 {
1632 m_imageInfoRecord.BBoxX = static_cast<int>(x);
1633 m_imageInfoRecord.BBoxH = static_cast<int>(h);
1634 }
1635 else
1636 {
1637 m_imageInfoRecord.BBoxX = 0;
1638 m_imageInfoRecord.BBoxH = m_image.height();
1639 }
1640 m_imageInfoRecord.xres = gsRes;
1641 m_imageInfoRecord.yres = gsRes;
1642 m_imageInfoRecord.colorspace = ColorSpaceCMYK;
1643 m_imageInfoRecord.type = ImageType7;
1644 m_image.setDotsPerMeterX ((int) (xres / 0.0254));
1645 m_image.setDotsPerMeterY ((int) (yres / 0.0254));
1646 m_pixelFormat = Format_YMCK_8;
1647 }
1648
blendImages(QImage & source,ScColor col)1649 void ScImgDataLoader_PS::blendImages(QImage &source, ScColor col)
1650 {
1651 int h = source.height();
1652 int w = source.width();
1653 int cyan, c, m, yc, k, cc, mm, yy, kk;
1654 col.getCMYK(&c, &m, &yc, &k);
1655 QRgb *p;
1656 QRgb *pq;
1657 for (int y=0; y < h; ++y )
1658 {
1659 p = (QRgb *)m_image.scanLine( y );
1660 pq = (QRgb *)source.scanLine( y );
1661 for (int x=0; x < w; ++x )
1662 {
1663 cyan = 255 - qRed(*pq);
1664 if (cyan != 0)
1665 {
1666 (c == 0) ? cc = qRed(*p) : cc = qMin(c * cyan / 255 + qRed(*p), 255);
1667 (m == 0) ? mm = qGreen(*p) : mm = qMin(m * cyan / 255 + qGreen(*p), 255);
1668 (yc == 0) ? yy = qBlue(*p) : yy = qMin(yc * cyan / 255 + qBlue(*p), 255);
1669 (k == 0) ? kk = qAlpha(*p) : kk = qMin(k * cyan / 255 + qAlpha(*p), 255);
1670 *p = qRgba(cc, mm, yy, kk);
1671 }
1672 p++;
1673 pq++;
1674 }
1675 }
1676 }
1677
preloadAlphaChannel(const QString & fn,int page,int gsRes,bool & hasAlpha)1678 bool ScImgDataLoader_PS::preloadAlphaChannel(const QString& fn, int page, int gsRes, bool& hasAlpha)
1679 {
1680 float xres, yres;
1681
1682 initialize();
1683
1684 hasAlpha = false;
1685 QFileInfo fi = QFileInfo(fn);
1686 if (!fi.exists())
1687 return false;
1688 QString ext = fi.suffix().toLower();
1689 QString tmpFile = QDir::toNativeSeparators(ScPaths::tempFileDir() + QString("sc%1.png").arg(qMax(1, page)));
1690 QString tmpFiles = QDir::toNativeSeparators(ScPaths::tempFileDir() + "sc%d.png");
1691 QString picFile = QDir::toNativeSeparators(fn);
1692 double x, y, b, h;
1693 bool found = false;
1694 found = parseData(fn);
1695 if (found)
1696 {
1697 ScTextStream ts2(&m_BBox, QIODevice::ReadOnly);
1698 ts2 >> x >> y >> b >> h;
1699 h = h * gsRes / 72.0;
1700 QStringList args;
1701 xres = gsRes;
1702 yres = gsRes;
1703 if (extensionIndicatesEPS(ext))
1704 {
1705 if (!m_BBoxInTrailer)
1706 args.append("-dEPSCrop");
1707 }
1708 args.append("-r"+QString::number(gsRes));
1709 args.append("-sOutputFile="+tmpFiles);
1710 args.append(picFile);
1711 // qDebug() << "scimgdataloader_ps(alpha):" << args;
1712 int retg = callGS(args);
1713 if (retg == 0)
1714 {
1715 m_image.load(tmpFile);
1716 if ((extensionIndicatesEPS(ext) && m_BBoxInTrailer) || (m_isRotated))
1717 {
1718 int ex = qRound(x * gsRes / 72.0);
1719 int ey = qRound(m_image.height() - h);
1720 int ew = qRound((b - x) * gsRes / 72.0);
1721 int eh = qRound(h - y * gsRes / 72.0);
1722 m_image = m_image.copy(ex, ey, ew, eh);
1723 }
1724 if ((!ScCore->havePNGAlpha()) || (m_isRotated))
1725 {
1726 int wi = m_image.width();
1727 int hi = m_image.height();
1728 QRgb alphaFF = qRgba(255,255,255,255);
1729 QRgb alpha00 = qRgba(255,255,255, 0);
1730 QRgb *s;
1731 for (int yi = 0; yi < hi; ++yi)
1732 {
1733 s = (QRgb*)(m_image.scanLine(yi));
1734 for (int xi = 0; xi < wi; ++xi)
1735 {
1736 if ((*s) == alphaFF)
1737 (*s) &= alpha00;
1738 s++;
1739 }
1740 }
1741 }
1742
1743 QStringList files = QStringList("sc*.png");
1744 files = QDir(ScPaths::tempFileDir()).entryList(files);
1745 for (int i=0; i < files.count(); ++i)
1746 QFile::remove(QDir::toNativeSeparators(ScPaths::tempFileDir() + files[i]));
1747
1748 hasAlpha = true;
1749 m_imageInfoRecord.actualPageNumber = page;
1750 m_imageInfoRecord.type = ImageTypeEPS;
1751 m_imageInfoRecord.colorspace = ColorSpaceRGB;
1752 m_image.setDotsPerMeterX ((int) (xres / 0.0254));
1753 m_image.setDotsPerMeterY ((int) (yres / 0.0254));
1754 return true;
1755 }
1756 qDebug() << "Ghostscript returned result" << retg;
1757 return false;
1758 }
1759 m_imageInfoRecord.actualPageNumber = page;
1760 return true;
1761 }
1762