Rev 24486 |
Rev 24689 |
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.
*/
/***************************************************************************
pslib.cpp - description
-------------------
begin : Sat May 26 2001
copyright : (C) 2001 by Franz Schmid
email : Franz.Schmid@altmuehlnet.de
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "pslib.h"
#include <cstdlib>
#include <QFileInfo>
#include <QImage>
#include <QColor>
#include <QFontInfo>
#include <QList>
#include <QByteArray>
#include <QRegExp>
#include <QBuffer>
#include <QStack>
#include "api/api_application.h"
#include "cmsettings.h"
#include "commonstrings.h"
#include "scconfig.h"
#include "pluginapi.h"
#include "pageitemiterator.h"
#include "pageitem_latexframe.h"
#include "pageitem_table.h"
#include "prefsmanager.h"
#include "scclocale.h"
#include "sccolorengine.h"
#include "scfonts.h"
#include "scribusapp.h"
#include "scribusdoc.h"
#include "scribuscore.h"
#include "selection.h"
#include "scpattern.h"
#include "scstreamfilter_ascii85.h"
#include "scstreamfilter_flate.h"
#include "tableutils.h"
#include "text/textlayoutpainter.h"
#include "ui/multiprogressdialog.h"
#include "util.h"
#include "util_formats.h"
#include "util_math.h"
#include "text/boxes.h"
using namespace TableUtils;
class PSPainter:public TextLayoutPainter
{
public:
PSPainter(ScribusDoc* Doc, uint argh, ScPage* page, bool master, PSLib* ps):
m_Doc(Doc),
m_argh(argh),
m_page(page),
m_master(master),
m_ps(ps)
{}
void drawGlyph(const GlyphCluster& gc) override;
void drawGlyphOutline(const GlyphCluster& gc, bool fill) override;
void drawLine(QPointF start, QPointF end) override;
void drawRect(QRectF rect) override;
void drawObject(PageItem* item) override;
private:
ScribusDoc* m_Doc {nullptr};
uint m_argh;
ScPage* m_page {nullptr};
bool m_master;
PSLib* m_ps {nullptr};
void applyTransform()
{
if (matrix() != QTransform())
{
m_ps->PutStream(m_ps->MatrixToStr(1.0, 0.0, 0.0, -1.0, x(), 0.0) + "\n");
m_ps->PutStream(m_ps->MatrixToStr(matrix().m11(), -matrix().m12(), matrix().m21(), -matrix().m22(), matrix().dx(), -matrix().dy()) + "\n");
m_ps->PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
}
}
};
void PSPainter::drawGlyph(const GlyphCluster& gc)
{
if (gc.isControlGlyphs() || gc.isEmpty())
return;
m_ps->PS_save();
applyTransform();
m_ps->PS_translate(x(), -(y() - fontSize()));
double current_x = 0.0;
for (const GlyphLayout& gl : gc.glyphs())
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
{
current_x += gl.xadvance * gl.scaleH;
continue;
}
m_ps->PS_save();
m_ps->PS_translate(gl.xoffset + current_x, -(fontSize() - fontSize() * gl.scaleV) - gl.yoffset);
if (gl.scaleH != 1.0 || (gl.scaleV != 1.0))
m_ps->PS_scale(gl.scaleH, gl.scaleV);
if (fillColor().color != CommonStrings::None)
m_ps->putColorNoDraw(fillColor().color, fillColor().shade);
m_ps->PS_showSub(gl.glyph, m_ps->FontSubsetMap[font().scName()], fontSize(), false);
m_ps->PS_restore();
current_x += gl.xadvance * gl.scaleH;
}
m_ps->PS_restore();
}
void PSPainter::drawGlyphOutline(const GlyphCluster& gc, bool fill)
{
if (gc.isControlGlyphs() || gc.isEmpty())
return;
if (strokeColor().color == CommonStrings::None)
return;
double h, s, v, k;
QVector<double> dum;
m_ps->PS_save();
applyTransform();
m_ps->PS_setlinewidth(strokeWidth());
m_ps->PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
m_ps->PS_setdash(Qt::SolidLine, 0, dum);
m_ps->PS_translate(x(), -(y() - fontSize()));
double current_x = 0.0;
for (const GlyphLayout& gl : gc.glyphs())
{
if (gl.glyph >= ScFace::CONTROL_GLYPHS)
{
current_x += gl.xadvance * gl.scaleH;
continue;
}
m_ps->PS_save();
FPointArray gly = font().glyphOutline(gl.glyph);
QTransform chma;
chma.scale((fontSize() * gc.scaleH()) / 10.0, (fontSize() * gc.scaleV()) / 10.0);
gly.map(chma);
m_ps->PS_translate(gl.xoffset + current_x, -(fontSize() - fontSize() * gc.scaleV()) - gl.yoffset);
if (fill)
{
m_ps->PS_save();
if (gc.scaleH() != 1.0 || gc.scaleV() != 1.0)
m_ps->PS_scale(gc.scaleH(), gc.scaleV());
m_ps->putColorNoDraw(fillColor().color, fillColor().shade);
m_ps->PS_showSub(gl.glyph, m_ps->FontSubsetMap[font().scName()], fontSize(), false);
m_ps->PS_restore();
}
m_ps->SetColor(strokeColor().color, strokeColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_stroke(h, s, v, k);
m_ps->SetClipPath(gly, true);
m_ps->PS_closepath();
m_ps->putColor(strokeColor().color, strokeColor().shade, false);
m_ps->PS_restore();
current_x += gl.xadvance * gl.scaleH;
}
m_ps->PS_restore();
}
void PSPainter::drawRect(QRectF rect)
{
double h {0.0}, s {0.0}, v {0.0}, k {0.0};
m_ps->PS_save();
applyTransform();
m_ps->PS_moveto(x() + rect.x(), -y() - rect.y());
m_ps->PS_lineto(x() + rect.x() + rect.width(), -y() - rect.y());
m_ps->PS_lineto(x() + rect.x() + rect.width(), -y() - rect.y() - rect.height());
m_ps->PS_lineto(x() + rect.x(), -y() - rect.y() - rect.height());
m_ps->PS_closepath();
m_ps->SetColor(fillColor().color, fillColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_fill(h, s, v, k);
m_ps->putColor(fillColor().color, fillColor().shade, true);
m_ps->PS_restore();
}
void PSPainter::drawLine(QPointF start, QPointF end)
{
QVector<double> dum;
dum.clear();
m_ps->PS_save();
applyTransform();
if (fillColor().color != CommonStrings::None)
{
double h = 0.0;
double s = 0.0;
double v = 0.0;
double k = 0.0;
m_ps->PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
m_ps->PS_setdash(Qt::SolidLine, 0, dum);
m_ps->SetColor(fillColor().color,fillColor().shade, &h, &s, &v, &k);
m_ps->PS_setcmykcolor_stroke(h, s, v, k);
}
m_ps->PS_setlinewidth(strokeWidth());
m_ps->PS_moveto(x() + start.x(), -y() - start.y());
m_ps->PS_lineto(x() + end.x(), -y() - end.y());
m_ps->putColor(fillColor().color, fillColor().shade, false);
m_ps->PS_restore();
}
void PSPainter::drawObject(PageItem* item)
{
m_ps->PS_save();
m_ps->PS_translate(x() + item->gXpos, -(y() + item->gYpos));
applyTransform();
if (scaleH() != 1 || scaleV() != 1)
m_ps->PS_scale(scaleH(), scaleV());
m_ps->ProcessItem(m_page, item, m_argh, m_master, true);
m_ps->PS_restore();
}
PSLib::PSLib(ScribusDoc* doc, PrintOptions &options, OutputFormat outputFmt, ColorList *docColors)
: m_Doc(doc), m_outputFormat(outputFmt)
{
Options = options;
User = "";
Creator = ScribusAPI::getVersionScribus();
Title = "";
FillColor = "0.0 0.0 0.0 0.0";
StrokeColor = "0.0 0.0 0.0 0.0";
FontDesc = "";
cmykCustomColors = "";
docCustomColors = "";
CMYKColorF cmykValues;
double c, m, y, k;
int spotCount = 1;
bool first = true;
spotMap.clear();
colorDesc.clear();
if (docColors != nullptr)
colorsToUse = *docColors;
else
m_Doc->getUsedColors(colorsToUse);
colorsToUse.setDocument(m_Doc);
for (auto itf = colorsToUse.begin(); itf != colorsToUse.end(); ++itf)
{
if (((itf->isSpotColor()) || (itf->isRegistrationColor())) && (Options.useSpotColors))
{
ScColorEngine::getCMYKValues(*itf, colorsToUse.document(), cmykValues);
cmykValues.getValues(c, m, y, k);
colorDesc += "/Spot" + QString::number(spotCount) + " { [ /Separation (";
if (itf->isRegistrationColor())
colorDesc += "All";
else
colorDesc += itf.key();
colorDesc += ")\n";
colorDesc += "/DeviceCMYK\n{\ndup " + ToStr(c) + "\nmul exch dup ";
colorDesc += ToStr(m) + "\nmul exch dup ";
colorDesc += ToStr(y) + "\nmul exch ";
colorDesc += ToStr(k) + " mul }] setcolorspace setcolor} bind def\n";
spotMap.insert(itf.key(), "Spot" + QString::number(spotCount));
++spotCount;
}
if ((itf.key() != "Cyan") && (itf.key() != "Magenta") && (itf.key() != "Yellow") && (itf.key() != "Black") && itf->isSpotColor())
{
ScColorEngine::getCMYKValues(colorsToUse[itf.key()], colorsToUse.document(), cmykValues);
cmykValues.getValues(c, m, y, k);
if (!first)
{
cmykCustomColors += "%%+ ";
docCustomColors += "%%+ ";
}
cmykCustomColors += ToStr(c) + " " + ToStr(m) + " ";
cmykCustomColors += ToStr(y) + " " + ToStr(k) + " (" + itf.key() + ")\n";
docCustomColors += "(" + itf.key() + ")\n";
first = false;
}
}
QMap<QString, QString> psNameMap;
SCFonts& allFonts = PrefsManager::instance().appPrefs.fontPrefs.AvailFonts;
QMap<QString, QMap<uint, QString> > docFonts;
doc->getUsedFonts(docFonts);
for (auto it = docFonts.begin(); it != docFonts.end(); ++it)
{
// Subset all TTF Fonts until the bug in the TTF-Embedding Code is fixed
// Subset also font whose postscript name conflicts with an already used font
// Subset always now with new boxes code.
ScFace &face (allFonts[it.key()]);
QMap<uint, QString>& usedGlyphs(it.value());
QString encodedName = face.psName().simplified().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" );
// Handle possible PostScript name conflict in oft/ttf fonts
int psNameIndex = 1;
QString initialName = encodedName;
while (psNameMap.contains(encodedName))
{
encodedName = QString("%1-%2").arg(initialName).arg(psNameIndex);
++psNameIndex;
}
FontDesc += "/" + encodedName + " " + IToStr(usedGlyphs.count() + 1) + " dict def\n";
FontDesc += encodedName + " begin\n";
for (auto ig = usedGlyphs.begin(); ig != usedGlyphs.end(); ++ig)
{
uint gid = ig.key();
FPointArray glyphOutline = face.glyphOutline(gid);
FontDesc += "/G" + IToStr(gid) + " { newpath\n";
FPoint np, np1, np2;
bool nPath = true;
if (glyphOutline.size() > 3)
{
for (int poi = 0; poi < glyphOutline.size() - 3; poi += 4)
{
if (glyphOutline.isMarker(poi))
{
FontDesc += "cl\n";
nPath = true;
continue;
}
if (nPath)
{
np = glyphOutline.point(poi);
FontDesc += ToStr(np.x()) + " " + ToStr(-np.y()) + " m\n";
nPath = false;
}
np = glyphOutline.point(poi + 1);
np1 = glyphOutline.point(poi + 3);
np2 = glyphOutline.point(poi + 2);
FontDesc += ToStr(np.x()) + " " + ToStr(-np.y()) + " " +
ToStr(np1.x()) + " " + ToStr(-np1.y()) + " " +
ToStr(np2.x()) + " " + ToStr(-np2.y()) + " cu\n";
}
}
FontDesc += "cl\n} bind def\n";
}
FontDesc += "end\n";
FontSubsetMap.insert(face.scName(), encodedName);
psNameMap.insert(encodedName, face.scName());
}
}
PSLib::~PSLib()
{
if (progressDialog)
progressDialog->deleteLater();
}
void PSLib::PutStream(const QString& c)
{
QByteArray utf8Array = c.toUtf8();
spoolStream.writeRawData(utf8Array.data(), utf8Array.length());
}
void PSLib::PutStream(const QByteArray& array, bool hexEnc)
{
if (hexEnc)
WriteASCII85Bytes(array);
else
spoolStream.writeRawData(array.data(), array.size());
}
void PSLib::PutStream(const char* array, int length, bool hexEnc)
{
if (hexEnc)
WriteASCII85Bytes((const unsigned char*) array, length);
else
spoolStream.writeRawData(array, length);
}
bool PSLib::PutImageToStream(ScImage& image, int plate)
{
bool writeSucceed = false;
ScASCII85EncodeFilter asciiEncode(&spoolStream);
ScFlateEncodeFilter flateEncode(&asciiEncode);
if (flateEncode.openFilter())
{
writeSucceed = image.writePSImageToFilter(&flateEncode, plate);
writeSucceed &= flateEncode.closeFilter();
}
return writeSucceed;
}
bool PSLib::PutImageToStream(ScImage& image, const QByteArray& mask, int plate)
{
bool writeSucceed = false;
ScASCII85EncodeFilter asciiEncode(&spoolStream);
ScFlateEncodeFilter flateEncode(&asciiEncode);
if (flateEncode.openFilter())
{
writeSucceed = image.writePSImageToFilter(&flateEncode, mask, plate);
writeSucceed &= flateEncode.closeFilter();
}
return writeSucceed;
}
bool PSLib::PutImageDataToStream(const QByteArray& image)
{
bool writeSucceed = false;
ScASCII85EncodeFilter asciiEncode(&spoolStream);
ScFlateEncodeFilter flateEncode(&asciiEncode);
if (flateEncode.openFilter())
{
writeSucceed = flateEncode.writeData(image, image.size());
writeSucceed &= flateEncode.closeFilter();
}
return writeSucceed;
}
bool PSLib::PutInterleavedImageMaskToStream(const QByteArray& image, const QByteArray& mask, bool gray)
{
int pending = 0;
unsigned char bytes[1505];
const unsigned char* imageData = (const unsigned char*) image.constData();
const unsigned char* maskData = (const unsigned char*) mask.constData();
bool writeSuccess = true;
int channels = gray ? 1 : 4;
int pixels = image.size() / channels;
assert((image.size() % channels) == 0);
assert( mask.size() >= pixels );
ScASCII85EncodeFilter asciiEncode(&spoolStream);
ScFlateEncodeFilter flateEncode(&asciiEncode);
if (!flateEncode.openFilter())
return false;
for (int i = 0; i < pixels; ++i)
{
bytes[pending++] = maskData [i];
bytes[pending++] = *imageData++; // cyan/black
if (channels > 1)
{
bytes[pending++] = *imageData++; // magenta
bytes[pending++] = *imageData++; // yellow
bytes[pending++] = *imageData++; // green
}
if (pending >= 1500)
{
writeSuccess &= flateEncode.writeData((const char* ) bytes, pending);
pending = 0;
}
}
// To close the stream
if (pending > 0)
writeSuccess &= flateEncode.writeData((const char* ) bytes, pending);
writeSuccess &= flateEncode.closeFilter();
return writeSuccess;
}
void PSLib::WriteASCII85Bytes(const QByteArray& array)
{
WriteASCII85Bytes((const unsigned char*) array.data(), array.size());
}
void PSLib::WriteASCII85Bytes(const unsigned char* array, int length)
{
ScASCII85EncodeFilter filter(&spoolStream);
filter.openFilter();
filter.writeData((const char*) array, length);
filter.closeFilter();
}
QString PSLib::ToStr(double c)
{
QString cc;
return cc.setNum(c);
}
QString PSLib::IToStr(int c)
{
QString cc;
return cc.setNum(c);
}
QString PSLib::MatrixToStr(double m11, double m12, double m21, double m22, double x, double y)
{
QString cc("[%1 %2 %3 %4 %5 %6]");
return cc.arg(m11).arg(m12).arg(m21).arg(m22).arg(x).arg(y);
}
void PSLib::PS_set_Info(const QString& art, const QString& was)
{
if (art == "Author")
User = was;
if (art == "Creator")
Creator = was;
if (art == "Title")
Title = was;
}
bool PSLib::PS_set_file(const QString& fn)
{
Spool.setFileName(fn);
if (Spool.exists())
Spool.remove();
bool ret = Spool.open(QIODevice::WriteOnly);
if (!ret)
{
PS_Error( tr("Failed to open file for writing : %1").arg(fn) );
return false;
}
spoolStream.setDevice(&Spool);
return true;
}
bool PSLib::PS_begin_doc(double x, double y, double width, double height, int numpage)
{
QString header = (m_outputFormat == OutputPS) ? "%!PS-Adobe-3.0\n" : "%!PS-Adobe-3.0 EPSF-3.0\n";
PutStream(header);
PutStream("%%For: " + User + "\n");
PutStream("%%Title: " + Title + "\n");
PutStream("%%Creator: " + Creator + "\n");
PutStream("%%Pages: " + IToStr(numpage) + "\n");
QString bbox, bboxH;
if ((width <= height) || (m_outputFormat == OutputEPS))
{
bbox = "%%BoundingBox: " + IToStr(qRound(x)) + " " + IToStr(qRound(y)) + " " + IToStr(qRound(width)) + " " + IToStr(qRound(height)) + "\n";
bboxH = "%%HiResBoundingBox: " + ToStr(x) + " " + ToStr(y) + " " + ToStr(width) + " " + ToStr(height) + "\n";
}
else
{
bbox = "%%BoundingBox: " + IToStr(qRound(x)) + " " + IToStr(qRound(y)) + " " + IToStr(qRound(height)) + " " + IToStr(qRound(width)) + "\n";
bboxH = "%%HiResBoundingBox: " + ToStr(x) + " " + ToStr(y) + " " + ToStr(height) + " " + ToStr(width) + "\n";
}
PutStream(bbox);
PutStream(bboxH);
if (!docCustomColors.isEmpty())
PutStream("%%DocumentCustomColors: " + docCustomColors);
if (!cmykCustomColors.isEmpty())
PutStream("%%CMYKCustomColor: " + cmykCustomColors);
PutStream("%%LanguageLevel: 3\n");
PutStream("%%EndComments\n");
if ((m_outputFormat == OutputPS) && Options.setDevParam)
{
PutStream("%%BeginDefaults\n");
if (width <= height)
PutStream("%%ViewingOrientation: 1 0 0 1\n");
else
PutStream("%%ViewingOrientation: 0 1 -1 0\n");
PutStream("%%EndDefaults\n");
}
else if (m_outputFormat == OutputEPS)
{
PutStream("%%BeginDefaults\n");
PutStream("%%ViewingOrientation: 1 0 0 1\n");
PutStream("%%EndDefaults\n");
}
QString prolog = "%%BeginProlog\n";
prolog += "/Scribusdict 100 dict def\n";
prolog += "Scribusdict begin\n";
prolog += "/sp {showpage} bind def\n";
prolog += "/oldsetgray /setgray load def\n";
prolog += "/cmyk {setcmykcolor} def\n";
prolog += "/m {moveto} bind def\n";
prolog += "/l {lineto} bind def\n";
prolog += "/li {lineto} bind def\n";
prolog += "/cu {curveto} bind def\n";
prolog += "/cl {closepath} bind def\n";
prolog += "/gs {gsave} bind def\n";
prolog += "/gr {grestore} bind def\n";
prolog += "/tr {translate} bind def\n";
prolog += "/ro {rotate} bind def\n";
prolog += "/sh {show} bind def\n";
prolog += "/shg {setcmykcolor moveto glyphshow} def\n";
prolog += "/shgsp {moveto glyphshow} def\n";
prolog += "/sc {scale} bind def\n";
prolog += "/se {selectfont} bind def\n";
prolog += "/sf {setfont} bind def\n";
prolog += "/sw {setlinewidth} bind def\n";
prolog += "/f {findfont} bind def\n";
prolog += "/fi {fill} bind def\n";
prolog += "/st {stroke} bind def\n";
prolog += "/shgf {gs dup scale begin cvx exec fill end gr} bind def\n";
prolog += "/shgs {gs dup 1 exch div currentlinewidth mul sw dup scale\n";
prolog += " begin cvx exec st end gr} bind def\n";
prolog += "/bEPS {\n";
prolog += " /b4_Inc_state save def\n";
prolog += " /dict_count countdictstack def\n";
prolog += " /op_count count 1 sub def\n";
prolog += " userdict begin\n";
prolog += " /showpage { } def\n";
prolog += " 0 setgray 0 setlinecap\n";
prolog += " 1 setlinewidth 0 setlinejoin\n";
prolog += " 10 setmiterlimit [ ] 0 setdash newpath\n";
prolog += " /languagelevel where\n";
prolog += " {pop languagelevel\n";
prolog += " 1 ne\n";
prolog += " {false setstrokeadjust false setoverprint\n";
prolog += " } if } if } bind def\n";
prolog += "/eEPS { count op_count sub {pop} repeat\n";
prolog += " countdictstack dict_count sub {end} repeat\n";
prolog += " b4_Inc_state restore } bind def\n";
prolog += " end\n";
if ((Options.cropMarks) || (Options.bleedMarks) || (Options.registrationMarks) || (Options.colorMarks))
prolog += "/rb { [ /Separation (All)\n/DeviceCMYK { dup 0 mul exch dup 0 mul exch dup 0 mul exch 1 mul }\n] setcolorspace setcolor} bind def\n";
prolog += "%%EndProlog\n";
PutStream(prolog);
PutStream("%%BeginSetup\n");
if (Options.includePDFMarks)
PutStream("/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse\n");
if (!FontDesc.isEmpty())
PutStream(FontDesc);
if ((!colorDesc.isEmpty()) && (!Options.outputSeparations))
PutStream(colorDesc);
if (GraySc)
{
QString grayCalc = "/setcmykcolor {exch 0.11 mul add exch 0.59 mul add exch 0.3 mul add\n";
grayCalc += " dup 1 gt {pop 1} if 1 exch sub oldsetgray} bind def\n";
grayCalc += "/setrgbcolor {0.11 mul exch 0.59 mul add exch 0.3 mul add\n";
grayCalc += " oldsetgray} bind def\n";
PutStream(grayCalc);
}
Optimization optim = m_optimization;
m_optimization = OptimizeSize;
QStringList patterns = m_Doc->getPatternDependencyList(m_Doc->getUsedPatterns());
for (int i = 0; i < patterns.count(); ++i)
{
QString patternName(patterns.at(i));
ScPattern pa = m_Doc->docPatterns[patternName];
for (PageItemIterator it(pa.items); *it; ++it)
{
PageItem* item = *it;
if ((item->isImageFrame()) && (item->imageIsAvailable) && (!item->Pfile.isEmpty()) && (item->printEnabled()) && (!Options.outputSeparations) && (Options.useColor))
{
if (!PS_ImageData(item, item->Pfile, item->itemName(), item->ImageProfile, item->UseEmbedded))
return false;
}
}
uint patHash = qHash(patternName);
PutStream("/Pattern" + QString::number(patHash) + " 8 dict def\n");
PutStream("Pattern" + QString::number(patHash) + " begin\n");
PutStream("/PatternType 1 def\n");
PutStream("/PaintType 1 def\n");
PutStream("/TilingType 1 def\n");
PutStream("/BBox [ 0 0 " + ToStr(pa.width) + " " + ToStr(pa.height) + "] def\n");
PutStream("/XStep " + ToStr(pa.width) + " def\n");
PutStream("/YStep " + ToStr(pa.height) + " def\n");
PutStream("/PaintProc {\n");
QIODevice *spStream = spoolStream.device();
QByteArray buf;
// Qt4 QBuffer b(buf);
QBuffer b(&buf);
b.open( QIODevice::WriteOnly );
spoolStream.setDevice(&b);
// PS_translate(pa.items.at(0)->gXpos, -pa.items.at(0)->gYpos);
for (int j = 0; j < pa.items.count(); ++j)
{
PageItem* item = pa.items.at(j);
PutStream("{\n");
PS_save();
PS_translate(item->gXpos, pa.height - item->gYpos);
ProcessItem(m_Doc->Pages->at(0), item, 0, false, true, true);
PS_restore();
PutStream("} exec\n");
}
spoolStream.setDevice(spStream);
PutStream(buf);
PutStream("} def\n");
PutStream("end\n");
}
m_optimization = optim;
bool errorOccured = false;
for (int ap = 0; ap < m_Doc->MasterPages.count() && !abortExport && !errorOccured; ++ap)
{
if (progressDialog)
{
progressDialog->setOverallProgress(ap);
progressDialog->setProgress("EMP", ap);
ScQApp->processEvents();
}
if (m_Doc->MasterItems.count() <= 0)
continue;
ScLayer ll;
ll.isPrintable = false;
ll.ID = 0;
for (int layerLevel = 0; layerLevel < m_Doc->Layers.count() && !abortExport && !errorOccured; ++layerLevel)
{
m_Doc->Layers.levelToLayer(ll, layerLevel);
if (!ll.isPrintable)
continue;
for (int api = 0; api < m_Doc->MasterItems.count() && !abortExport; ++api)
{
PageItem *it = m_Doc->MasterItems.at(api);
if (progressDialog)
ScQApp->processEvents();
if ((it->m_layerID != ll.ID) || (!it->printEnabled()))
continue;
double bLeft, bRight, bBottom, bTop;
GetBleeds(m_Doc->MasterPages.at(ap), bLeft, bRight, bBottom, bTop);
double x1 = m_Doc->MasterPages.at(ap)->xOffset() - bLeft;
double y1 = m_Doc->MasterPages.at(ap)->yOffset() - bTop;
double w1 = m_Doc->MasterPages.at(ap)->width() + bLeft + bRight;
double h1 = m_Doc->MasterPages.at(ap)->height()+ bBottom + bTop;
double lw = it->visualLineWidth();
double x2 = it->BoundingX - lw / 2.0;
double y2 = it->BoundingY - lw / 2.0;
double w2 = qMax(it->BoundingW + lw, 1.0);
double h2 = qMax(it->BoundingH + lw, 1.0);
if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x1, y1, w1, h1)))
continue;
if ((it->OwnPage != m_Doc->MasterPages.at(ap)->pageNr()) && (it->OwnPage != -1))
continue;
if ((m_optimization == OptimizeSize) && it->isImageFrame() && it->imageIsAvailable && (!it->Pfile.isEmpty()) && it->printEnabled() && (!Options.outputSeparations) && Options.useColor)
{
errorOccured = !PS_ImageData(it, it->Pfile, it->itemName(), it->ImageProfile, it->UseEmbedded);
if (errorOccured) break;
}
PS_TemplateStart(QString("mp_obj_%1_%2").arg(ap).arg(qHash(it)));
ProcessItem(m_Doc->MasterPages.at(ap), it, ap+1, true);
PS_TemplateEnd();
}
if (errorOccured) break;
}
}
PutStream("%%EndSetup\n");
return (!errorOccured);
}
QString PSLib::PSEncode(const QString& in)
{
static QRegExp badchars("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]");
QString tmp(in.simplified().replace( badchars, "_" ));
return tmp;
}
void PSLib::PS_TemplateStart(const QString& Name)
{
PutStream("/" + PSEncode(Name) + "\n{\n");
}
void PSLib::PS_UseTemplate(const QString& Name)
{
PutStream(PSEncode(Name) + "\n");
}
void PSLib::PS_TemplateEnd()
{
PutStream("} bind def\n");
}
void PSLib::PS_begin_page(ScPage* pg, MarginStruct* Ma, bool clipping)
{
double bleedRight = 0.0;
double bleedLeft = 0.0;
double markOffs = 0.0;
if ((Options.cropMarks) || (Options.bleedMarks) || (Options.registrationMarks) || (Options.colorMarks))
markOffs = Options.markLength + Options.markOffset;
if ((Options.registrationMarks) || (Options.colorMarks))
markOffs = qMax(markOffs, Options.markOffset + 20.0);
GetBleeds(pg, bleedLeft, bleedRight);
double maxBoxX = pg->width() + bleedLeft + bleedRight + markOffs * 2.0;
double maxBoxY = pg->height() + Options.bleeds.bottom() + Options.bleeds.top() + markOffs * 2.0;
PageIndex++;
PutStream("%%Page: " + IToStr(PageIndex) + " " + IToStr(PageIndex) + "\n");
if (m_outputFormat == OutputPS)
{
if (pg->orientation() == 0)
{
PutStream("%%PageOrientation: Portrait\n");
PutStream("%%PageBoundingBox: 0 0 " + IToStr(qRound(maxBoxX)) + " " + IToStr(qRound(maxBoxY)) + "\n");
PutStream("%%PageCropBox: " + ToStr(bleedLeft + markOffs) + " " + ToStr(Options.bleeds.bottom() + markOffs) + " " + ToStr(maxBoxX - bleedRight - markOffs * 2.0) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs * 2.0) + "\n");
}
else
{
PutStream("%%PageOrientation: Landscape\n");
PutStream("%%PageBoundingBox: 0 0 " + IToStr(qRound(maxBoxY)) + " " + IToStr(qRound(maxBoxX)) + "\n");
PutStream("%%PageCropBox: " + ToStr(bleedLeft + markOffs) + " " + ToStr(Options.bleeds.bottom() + markOffs) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs * 2.0) + " " + ToStr(maxBoxX - bleedRight - markOffs * 2.0) + "\n");
}
}
PutStream("Scribusdict begin\n");
if ((m_outputFormat == OutputPS) && (Options.setDevParam))
{
if (pg->orientation() == 0)
PutStream("<< /PageSize [ " + ToStr(maxBoxX) + " " + ToStr(maxBoxY) + " ]\n");
else
PutStream("<< /PageSize [ " + ToStr(maxBoxY) + " " + ToStr(maxBoxX) + " ]\n");
PutStream(">> setpagedevice\n");
}
PutStream("save\n");
if ((pg->orientation() == 1) && (m_outputFormat == OutputPS))
PutStream("90 rotate 0 " + IToStr(qRound(maxBoxY)) + " neg translate\n");
PutStream("/DeviceCMYK setcolorspace\n");
// Clip to bleeds
QString clipStr;
double bbWidth = pg->width() + bleedLeft + bleedRight;
double bbHeight = pg->height() + Options.bleeds.bottom() + Options.bleeds.top();
clipStr += ToStr(markOffs) + " " + ToStr(markOffs) + " m\n";
clipStr += ToStr(markOffs + bbWidth) + " " + ToStr(markOffs) + " li\n";
clipStr += ToStr(markOffs + bbWidth) + " " + ToStr(markOffs + bbHeight) + " li\n";
clipStr += ToStr(markOffs) + " " + ToStr(markOffs + bbHeight) + " li cl clip newpath\n";
PutStream(clipStr);
// Move to page origin
PutStream(ToStr(bleedLeft + markOffs) + " " + ToStr(Options.bleeds.bottom() + markOffs) + " tr\n");
m_currentPage = pg;
// Clip to margins if requested
if (clipping)
{
QString clipPath = ToStr(Ma->left()) + " " + ToStr(Ma->bottom()) + " m\n";
clipPath += ToStr(pg->width() - Ma->right()) + " " + ToStr(Ma->bottom()) + " li\n";
clipPath += ToStr(pg->width() - Ma->right()) + " " + ToStr(pg->height() - Ma->top()) + " li\n";
clipPath += ToStr(Ma->left()) + " " + ToStr(pg->height() - Ma->top()) + " li cl clip newpath\n";
PutStream(clipPath);
}
}
void PSLib::PS_end_page()
{
PutStream("%%PageTrailer\nrestore\n");
double markOffs = 0.0;
if ((Options.cropMarks) || (Options.bleedMarks) || (Options.registrationMarks) || (Options.colorMarks))
markOffs = Options.markLength + Options.markOffset;
if ((Options.registrationMarks) || (Options.colorMarks))
markOffs = qMax(markOffs, Options.markOffset + 20.0);
double markDelta = markOffs - (Options.markLength + Options.markOffset);
double bleedRight, bleedLeft;
GetBleeds(m_currentPage, bleedLeft, bleedRight);
double maxBoxX = m_currentPage->width() + bleedLeft + bleedRight + markOffs * 2.0;
double maxBoxY = m_currentPage->height() + Options.bleeds.bottom() + Options.bleeds.top() + markOffs * 2.0;
PutStream("gs\n");
if ((m_currentPage->orientation() == 1) && (m_outputFormat == OutputPS))
PutStream("90 rotate 0 " + IToStr(qRound(maxBoxY)) + " neg translate\n");
if ((Options.cropMarks) || (Options.bleedMarks) || (Options.registrationMarks) || (Options.colorMarks))
{
PutStream("gs\n");
PS_setlinewidth(0.5);
PutStream("[] 0 setdash\n");
PutStream("0 setlinecap\n");
PutStream("0 setlinejoin\n");
PutStream("1 rb\n");
if (Options.cropMarks)
{
// Bottom Left
PutStream(ToStr(markDelta) + " " + ToStr(markOffs + Options.bleeds.bottom()) + " m\n");
PutStream(ToStr(markDelta + Options.markLength) + " " + ToStr(markOffs + Options.bleeds.bottom()) + " li\n");
PutStream("st\n");
PutStream(ToStr(markOffs + bleedLeft) + " " + ToStr(markDelta) + " m\n");
PutStream(ToStr(markOffs + bleedLeft) + " " + ToStr(markDelta + Options.markLength) + " li\n");
PutStream("st\n");
// Top Left
PutStream(ToStr(markDelta) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs) + " m\n");
PutStream(ToStr(markDelta + Options.markLength) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(markOffs + bleedLeft) + " " + ToStr(maxBoxY - markDelta) + " m\n");
PutStream(ToStr(markOffs + bleedLeft) + " " + ToStr(maxBoxY - markDelta - Options.markLength) + " li\n");
PutStream("st\n");
// Bottom Right
PutStream(ToStr(maxBoxX - markDelta) + " " + ToStr(markOffs + Options.bleeds.bottom()) + " m\n");
PutStream(ToStr(maxBoxX - markDelta - Options.markLength) + " " + ToStr(markOffs + Options.bleeds.bottom()) + " li\n");
PutStream("st\n");
PutStream(ToStr(maxBoxX - bleedRight - markOffs) + " " + ToStr(markDelta) + " m\n");
PutStream(ToStr(maxBoxX - bleedRight - markOffs) + " " + ToStr(markDelta + Options.markLength) + " li\n");
PutStream("st\n");
// Top Right
PutStream(ToStr(maxBoxX - markDelta) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs) + " m\n");
PutStream(ToStr(maxBoxX - markDelta - Options.markLength) + " " + ToStr(maxBoxY - Options.bleeds.top() - markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(maxBoxX - bleedRight - markOffs) + " " + ToStr(maxBoxY - markDelta) + " m\n");
PutStream(ToStr(maxBoxX - bleedRight - markOffs) + " " + ToStr(maxBoxY - markDelta - Options.markLength) + " li\n");
PutStream("st\n");
}
if (Options.bleedMarks)
{
PutStream("gs\n");
PutStream("[3 1 1 1] 0 setdash\n");
// Bottom Left
PutStream(ToStr(markDelta) + " " + ToStr(markOffs) + " m\n");
PutStream(ToStr(markDelta + Options.markLength) + " " + ToStr(markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(markOffs) + " " + ToStr(markDelta) + " m\n");
PutStream(ToStr(markOffs) + " " + ToStr(markDelta + Options.markLength) + " li\n");
PutStream("st\n");
// Top Left
PutStream(ToStr(markDelta) + " " + ToStr(maxBoxY - markOffs) + " m\n");
PutStream(ToStr(markDelta + Options.markLength) + " " + ToStr(maxBoxY - markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(markOffs) + " " + ToStr(maxBoxY - markDelta) + " m\n");
PutStream(ToStr(markOffs) + " " + ToStr(maxBoxY - markDelta - Options.markLength) + " li\n");
PutStream("st\n");
// Bottom Right
PutStream(ToStr(maxBoxX - markDelta) + " " + ToStr(markOffs) + " m\n");
PutStream(ToStr(maxBoxX - markDelta - Options.markLength) + " " + ToStr(markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(maxBoxX - markOffs) + " " + ToStr(markDelta) + " m\n");
PutStream(ToStr(maxBoxX - markOffs) + " " + ToStr(markDelta + Options.markLength) + " li\n");
PutStream("st\n");
// Top Right
PutStream(ToStr(maxBoxX - markDelta) + " " + ToStr(maxBoxY - markOffs) + " m\n");
PutStream(ToStr(maxBoxX - markDelta - Options.markLength) + " " + ToStr(maxBoxY - markOffs) + " li\n");
PutStream("st\n");
PutStream(ToStr(maxBoxX - markOffs) + " " + ToStr(maxBoxY - markDelta) + " m\n");
PutStream(ToStr(maxBoxX - markOffs) + " " + ToStr(maxBoxY - markDelta - Options.markLength) + " li\n");
PutStream("st\n");
PutStream("gr\n");
}
if (Options.registrationMarks)
{
double regDelta = markOffs - Options.markOffset;
QString regCross = "0 7 m\n14 7 li\n7 0 m\n7 14 li\n13 7 m\n13 10.31383 10.31383 13 7 13 cu\n3.68629 13 1 10.31383 1 7 cu\n1 3.68629 3.68629 1 7 1 cu\n";
regCross += "10.31383 1 13 3.68629 13 7 cu\ncl\n10.5 7 m\n10.5 8.93307 8.93307 10.5 7 10.5 cu\n5.067 10.5 3.5 8.93307 3.5 7 cu\n";
regCross += "3.5 5.067 5.067 3.5 7 3.5 cu\n8.93307 3.5 10.5 5.067 10.5 7 cu\ncl\nst\n";
PutStream("gs\n");
PutStream(ToStr(maxBoxX / 2.0 - 7.0) + " " + ToStr(regDelta - 17) + " tr\n");
PutStream(regCross);
PutStream("gr\n");
PutStream("gs\n");
PutStream(ToStr(regDelta - 17) + " " + ToStr(maxBoxY / 2.0 - 7.0) + " tr\n");
PutStream(regCross);
PutStream("gr\n");
PutStream("gs\n");
PutStream(ToStr(maxBoxX / 2.0 - 7.0) + " " + ToStr(maxBoxY - regDelta + 3.0) + " tr\n");
PutStream(regCross);
PutStream("gr\n");
PutStream("gs\n");
PutStream(ToStr(maxBoxX - regDelta + 3.0) + " " + ToStr(maxBoxY / 2.0 - 7.0) + " tr\n");
PutStream(regCross);
PutStream("gr\n");
}
if (Options.colorMarks)
{
double startX = markOffs + bleedLeft + 6.0;
double startY = maxBoxY - markOffs + Options.markOffset + 2.0;
PutStream("0 0 0 1 cmyk\n");
double col = 1.0;
for (int bl = 0; bl < 11; bl++)
{
PutStream("0 0 0 " + ToStr(col) + " cmyk\n");
PutStream(ToStr(startX + bl * 14.0) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX + bl * 14.0) + " " + ToStr(startY) + " 14 14 rectstroke\n");
col -= 0.1;
}
startX = maxBoxX - bleedRight - markOffs - 20.0;
PutStream("0 0 0 0.5 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 0 0.5 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 0.5 0 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0.5 0 0 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("1 1 0 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("1 0 1 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 1 1 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 0 1 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("0 1 0 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
startX -= 14.0;
PutStream("1 0 0 0 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectfill\n");
PutStream("0 0 0 1 cmyk\n");
PutStream(ToStr(startX) + " " + ToStr(startY) + " 14 14 rectstroke\n");
}
PutStream("gr\n");
}
PutStream("gr\n");
PutStream("sp\n");
PutStream("end\n");
}
void PSLib::PS_curve(double x1, double y1, double x2, double y2, double x3, double y3)
{
PutStream(ToStr(x1) + " " + ToStr(y1) + " " + ToStr(x2) + " " + ToStr(y2) + " " + ToStr(x3) + " " + ToStr(y3) + " cu\n");
}
void PSLib::PS_moveto(double x, double y)
{
PutStream(ToStr(x) + " " + ToStr(y) + " m\n");
}
void PSLib::PS_lineto(double x, double y)
{
PutStream(ToStr(x) + " " + ToStr(y) + " li\n");
}
void PSLib::PS_closepath()
{
PutStream("cl\n");
}
void PSLib::PS_translate(double x, double y)
{
PutStream(ToStr(x) + " " + ToStr(y) + " tr\n");
}
void PSLib::PS_scale(double x, double y)
{
PutStream(ToStr(x) + " " + ToStr(y) + " sc\n");
}
void PSLib::PS_rotate(double x)
{
PutStream(ToStr(x) + " ro\n");
}
void PSLib::PS_clip(bool mu)
{
PutStream(mu ? "eoclip newpath\n" : "clip newpath\n");
}
void PSLib::PS_save()
{
PutStream("gs\n");
}
void PSLib::PS_restore()
{
PutStream("gr\n");
}
void PSLib::PS_setcmykcolor_fill(double c, double m, double y, double k)
{
FillColor = ToStr(c) + " " + ToStr(m) + " " + ToStr(y) + " " + ToStr(k);
}
void PSLib::PS_setcmykcolor_dummy()
{
PutStream("0 0 0 0 cmyk\n");
}
void PSLib::PS_setcmykcolor_stroke(double c, double m, double y, double k)
{
StrokeColor = ToStr(c) + " " + ToStr(m) + " " + ToStr(y) + " " + ToStr(k);
}
void PSLib::PS_setlinewidth(double w)
{
PutStream(ToStr(w) + " sw\n");
LineW = w;
}
void PSLib::PS_setdash(Qt::PenStyle st, double offset, QVector<double> dash)
{
if (dash.count() != 0)
{
PutStream("[ ");
QVector<double>::iterator it;
for ( it = dash.begin(); it != dash.end(); ++it )
{
PutStream(ToStr(*it) + " ");
}
PutStream("] " + ToStr(offset) + " setdash\n");
}
else
PutStream("[" + getDashString(st, LineW) + "] 0 setdash\n");
}
void PSLib::PS_setcapjoin(Qt::PenCapStyle ca, Qt::PenJoinStyle jo)
{
switch (ca)
{
case Qt::FlatCap:
PutStream("0 setlinecap\n");
break;
case Qt::SquareCap:
PutStream("2 setlinecap\n");
break;
case Qt::RoundCap:
PutStream("1 setlinecap\n");
break;
default:
PutStream("0 setlinecap\n");
break;
}
switch (jo)
{
case Qt::MiterJoin:
PutStream("0 setlinejoin\n");
break;
case Qt::BevelJoin:
PutStream("2 setlinejoin\n");
break;
case Qt::RoundJoin:
PutStream("1 setlinejoin\n");
break;
default:
PutStream("0 setlinejoin\n");
break;
}
}
void PSLib::PS_fill()
{
if (fillRule)
PutStream(FillColor + " cmyk eofill\n");
else
PutStream(FillColor + " cmyk fill\n");
}
void PSLib::PS_fillspot(const QString& color, double shade)
{
if (fillRule)
PutStream(ToStr(shade / 100.0) + " " + spotMap[color] + " eofill\n");
else
PutStream(ToStr(shade / 100.0) + " " + spotMap[color] + " fill\n");
}
void PSLib::PS_strokespot(const QString& color, double shade)
{
PutStream(ToStr(shade / 100.0) + " " + spotMap[color] + " st\n");
}
void PSLib::PS_stroke()
{
PutStream(StrokeColor + " cmyk st\n");
}
void PSLib::PS_fill_stroke()
{
PS_save();
PS_fill();
PS_restore();
PS_stroke();
}
void PSLib::PS_newpath()
{
PutStream("newpath\n");
}
void PSLib::PS_show(double x, double y)
{
PS_moveto(x, y);
PutStream("/hyphen glyphshow\n");
}
void PSLib::PS_showSub(uint chr, const QString& font, double size, bool stroke)
{
PutStream(" (G" + IToStr(chr) + ") " + font + " " + ToStr(size / 10.0) + " ");
PutStream(stroke ? "shgs\n" : "shgf\n");
}
bool PSLib::PS_ImageData(PageItem *item, const QString& fn, const QString& Name, const QString& Prof, bool UseEmbedded)
{
bool dummy;
QByteArray tmp;
QFileInfo fi = QFileInfo(fn);
QString ext = fi.suffix().toLower();
if (ext.isEmpty())
ext = getImageType(fn);
if (extensionIndicatesEPS(ext) && (item->pixm.imgInfo.type != ImageType7))
{
if (loadRawText(fn, tmp))
{
PutStream("currentfile 1 (%ENDEPSDATA) /SubFileDecode filter /ReusableStreamDecode filter\n");
PutStream("%%BeginDocument: " + fi.fileName() + "\n");
if (getDouble(tmp.mid(0, 4), true) == 0xC5D0D3C6)
{
char* data = tmp.data();
uint startPos = getDouble(tmp.mid(4, 4), false);
uint length = getDouble(tmp.mid(8, 4), false);
PutStream(data+startPos, length, false);
}
else
PutStream(tmp, false);
PutStream("\n%ENDEPSDATA\n");
PutStream("%%EndDocument\n");
PutStream("/" + PSEncode(Name) + "Bild exch def\n");
return true;
}
return false;
}
ScImage image;
QByteArray imgArray;
image.imgInfo.valid = false;
image.imgInfo.clipPath = "";
image.imgInfo.PDSpathData.clear();
image.imgInfo.layerInfo.clear();
image.imgInfo.RequestProps = item->pixm.imgInfo.RequestProps;
image.imgInfo.isRequest = item->pixm.imgInfo.isRequest;
CMSettings cms(item->doc(), Prof, item->ImageIntent);
cms.allowColorManagement(true);
cms.setUseEmbeddedProfile(UseEmbedded);
if (!image.loadPicture(fn, item->pixm.imgInfo.actualPageNumber, cms, ScImage::CMYKData, 300, &dummy))
{
PS_Error_ImageLoadFailure(fn);
return false;
}
image.applyEffect(item->effectsInUse, colorsToUse, true);
QByteArray maskArray;
if (item->pixm.imgInfo.type != ImageType7)
{
bool alphaLoaded = image.getAlpha(fn, item->pixm.imgInfo.actualPageNumber, maskArray, false, true, 300);
if (!alphaLoaded)
{
PS_Error_MaskLoadFailure(fn);
return false;
}
}
if ((maskArray.size() > 0) && (item->pixm.imgInfo.type != ImageType7))
{
PutStream("currentfile /ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
if (!PutImageToStream(image, maskArray, -1))
{
PS_Error_ImageDataWriteFailure();
return false;
}
PutStream("/" + PSEncode(Name) + "Bild exch def\n");
}
else
{
PutStream("currentfile /ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n");
if (!PutImageToStream(image, -1))
{
PS_Error_ImageDataWriteFailure();
return false;
}
PutStream("/" + PSEncode(Name) + "Bild exch def\n");
imgArray.resize(0);
}
return true;
}
bool PSLib::PS_image(PageItem *item, double x, double y, const QString& fn, double scalex, double scaley, const QString& Prof, bool UseEmbedded, const QString& Name)
{
bool dummy;
QByteArray tmp;
QFileInfo fi = QFileInfo(fn);
QString ext = fi.suffix().toLower();
if (ext.isEmpty())
ext = getImageType(fn);
if (extensionIndicatesEPS(ext) && (item->pixm.imgInfo.type != ImageType7))
{
if (loadRawText(fn, tmp))
{
PutStream("bEPS\n");
PutStream(ToStr(PrefsManager::instance().appPrefs.extToolPrefs.gs_Resolution / 72.0 * scalex) + " " + ToStr(PrefsManager::instance().appPrefs.extToolPrefs.gs_Resolution / 72.0 * scaley) + " sc\n");
PutStream(ToStr(-item->BBoxX+x * scalex) + " " + ToStr(y * scalex) + " tr\n");
int h = item->pixm.height();
PutStream("0 " + ToStr(h*scaley) + " tr\n");
PutStream(ToStr(-item->imageRotation()) + " ro\n");
PutStream("0 " + ToStr(-h*scaley) + " tr\n");
if (!Name.isEmpty())
{
PutStream(PSEncode(Name) + "Bild cvx exec\n");
PutStream(PSEncode(Name) + "Bild resetfile\n");
}
else
{
PutStream("%%BeginDocument: " + fi.fileName() + "\n");
if (getDouble(tmp.mid(0, 4), true) == 0xC5D0D3C6)
{
char* data = tmp.data();
uint startPos = getDouble(tmp.mid(4, 4), false);
uint length = getDouble(tmp.mid(8, 4), false);
PutStream(data+startPos, length, false);
}
else
PutStream(tmp);
PutStream("\n%%EndDocument\n");
}
PutStream("eEPS\n");
return true;
}
return false;
}
ScImage image;
image.imgInfo.valid = false;
image.imgInfo.clipPath = "";
image.imgInfo.PDSpathData.clear();
image.imgInfo.layerInfo.clear();
image.imgInfo.RequestProps = item->pixm.imgInfo.RequestProps;
image.imgInfo.isRequest = item->pixm.imgInfo.isRequest;
CMSettings cms(item->doc(), Prof, item->ImageIntent);
cms.allowColorManagement(true);
cms.setUseEmbeddedProfile(UseEmbedded);
int resolution = 300;
if (item->isLatexFrame())
resolution = item->asLatexFrame()->realDpi();
else if (item->pixm.imgInfo.type == ImageType7)
resolution = 72;
// int resolution = (item->pixm.imgInfo.type == ImageType7) ? 72 : 300;
if ( !image.loadPicture(fn, item->pixm.imgInfo.actualPageNumber, cms, ScImage::CMYKData, resolution, &dummy) )
{
PS_Error_ImageLoadFailure(fn);
return false;
}
image.applyEffect(item->effectsInUse, colorsToUse, true);
int w = image.width();
int h = image.height();
PutStream(ToStr(x*scalex) + " " + ToStr(y*scaley) + " tr\n");
PutStream("0 " + ToStr(h*scaley) + " tr\n");
PutStream(ToStr(-item->imageRotation()) + " ro\n");
PutStream("0 " + ToStr(-h*scaley) + " tr\n");
if ((extensionIndicatesPDF(ext)) && (!item->isLatexFrame()))
{
scalex *= PrefsManager::instance().appPrefs.extToolPrefs.gs_Resolution / 300.0;
scaley *= PrefsManager::instance().appPrefs.extToolPrefs.gs_Resolution / 300.0;
}
// PutStream(ToStr(x*scalex) + " " + ToStr(y*scaley) + " tr\n");
PutStream(ToStr(qRound(scalex*w)) + " " + ToStr(qRound(scaley*h)) + " sc\n");
PutStream(((!DoSep) && (!GraySc)) ? "/DeviceCMYK setcolorspace\n" : "/DeviceGray setcolorspace\n");
QByteArray maskArray;
ScImage img2;
img2.imgInfo.clipPath = "";
img2.imgInfo.PDSpathData.clear();
img2.imgInfo.layerInfo.clear();
img2.imgInfo.RequestProps = item->pixm.imgInfo.RequestProps;
img2.imgInfo.isRequest = item->pixm.imgInfo.isRequest;
if (item->pixm.imgInfo.type != ImageType7)
{
bool alphaLoaded = img2.getAlpha(fn, item->pixm.imgInfo.actualPageNumber, maskArray, false, true, resolution);
if (!alphaLoaded)
{
PS_Error_MaskLoadFailure(fn);
return false;
}
}
if ((maskArray.size() > 0) && (item->pixm.imgInfo.type != ImageType7))
{
int plate = DoSep ? Plate : (GraySc ? -2 : -1);
// JG - Experimental code using Type3 image instead of patterns
PutStream("<< /ImageType 3\n");
PutStream(" /DataDict <<\n");
PutStream(" /ImageType 1\n");
PutStream(" /Width " + IToStr(w) + "\n");
PutStream(" /Height " + IToStr(h) + "\n");
PutStream(" /BitsPerComponent 8\n");
PutStream( (GraySc || DoSep) ? " /Decode [1 0]\n" : " /Decode [0 1 0 1 0 1 0 1]\n");
PutStream(" /ImageMatrix [" + IToStr(w) + " 0 0 " + IToStr(-h) + " 0 " + IToStr(h) + "]\n");
if (Name.length() > 0)
PutStream(" /DataSource " + PSEncode(Name) + "Bild\n");
else
PutStream(" /DataSource currentfile /ASCII85Decode filter /FlateDecode filter\n");
PutStream(" >>\n");
PutStream(" /MaskDict <<\n");
PutStream(" /ImageType 1\n");
PutStream(" /Width " + IToStr(w) + "\n");
PutStream(" /Height " + IToStr(h) + "\n");
PutStream(" /BitsPerComponent 8\n");
PutStream(" /Decode [1 0]\n");
PutStream(" /ImageMatrix [" + IToStr(w) + " 0 0 " + IToStr(-h) + " 0 " + IToStr(h) + "]\n");
PutStream(" >>\n");
PutStream(" /InterleaveType 1\n");
PutStream(">>\n");
PutStream("image\n");
if (Name.isEmpty())
{
if (!PutImageToStream(image, maskArray, plate))
{
PS_Error_ImageDataWriteFailure();
return false;
}
}
else
{
PutStream(PSEncode(Name) + "Bild resetfile\n");
//PutStream(PSEncode(Name) + "Mask resetfile\n");
}
}
else
{
PutStream("<< /ImageType 1\n");
PutStream(" /Width " + IToStr(w) + "\n");
PutStream(" /Height " + IToStr(h) + "\n");
PutStream(" /BitsPerComponent 8\n");
if (DoSep)
PutStream(" /Decode [1 0]\n");
else
PutStream( GraySc ? " /Decode [1 0]\n" : " /Decode [0 1 0 1 0 1 0 1]\n");
PutStream(" /ImageMatrix [" + IToStr(w) + " 0 0 " + IToStr(-h) + " 0 " + IToStr(h) + "]\n");
if (!Name.isEmpty())
{
PutStream(" /DataSource " + PSEncode(Name) + "Bild >>\n");
PutStream("image\n");
PutStream(PSEncode(Name) + "Bild resetfile\n");
}
else
{
int plate = DoSep ? Plate : (GraySc ? -2 : -1);
PutStream(" /DataSource currentfile /ASCII85Decode filter /FlateDecode filter >>\n");
PutStream("image\n");
if (!PutImageToStream(image, plate))
{
PS_Error_ImageDataWriteFailure();
return false;
}
}
}
return true;
}
void PSLib::PS_plate(int nr, const QString& name)
{
switch (nr)
{
case 0:
PutStream("%%PlateColor Black\n");
PutStream("/setcmykcolor {exch pop exch pop exch pop 1 exch sub oldsetgray} bind def\n");
PutStream("/setrgbcolor {pop pop pop 1 oldsetgray} bind def\n");
break;
case 1:
PutStream("%%PlateColor Cyan\n");
PutStream("/setcmykcolor {pop pop pop 1 exch sub oldsetgray} bind def\n");
PutStream("/setrgbcolor {pop pop oldsetgray} bind def\n");
break;
case 2:
PutStream("%%PlateColor Magenta\n");
PutStream("/setcmykcolor {pop pop exch pop 1 exch sub oldsetgray} bind def\n");
PutStream("/setrgbcolor {pop exch pop oldsetgray} bind def\n");
break;
case 3:
PutStream("%%PlateColor Yellow\n");
PutStream("/setcmykcolor {pop exch pop exch pop 1 exch sub oldsetgray} bind def\n");
PutStream("/setrgbcolor {exch pop exch pop oldsetgray} bind def\n");
break;
default:
PutStream("%%PlateColor " + name + "\n");
PutStream("/setcmykcolor {exch 0.11 mul add exch 0.59 mul add exch 0.3 mul add dup 1 gt {pop 1} if 1 exch sub oldsetgray} bind def\n");
PutStream("/setrgbcolor {0.11 mul exch 0.59 mul add exch 0.3 mul add oldsetgray} bind def\n");
break;
}
Plate = nr;
currentSpot = name;
DoSep = true;
}
void PSLib::PS_setGray()
{
GraySc = true;
}
void PSLib::PDF_Bookmark(const QString& text, uint Seite)
{
PutStream("[/Title (" + text + ") /Page " + IToStr(Seite) + " /View [/Fit]\n");
PutStream("/OUT pdfmark\n");
}
void PSLib::PDF_Annotation(PageItem *item, const QString& text, double x, double y, double b, double h)
{
PutStream("[\n/Rect [ " + ToStr(x) + " " + ToStr(y) + " " + ToStr(b) + " " + ToStr(h) + " ]\n");
switch (item->annotation().Type())
{
case 0:
case Annotation::Text:
PutStream("/Subtype /Text\n");
PutStream("/Contents (" + text + ")\n/Open false\n");
break;
case 1:
case Annotation::Link:
PutStream("/Subtype /Link\n");
if (item->annotation().ActionType() == Annotation::Action_GoTo)
{
PutStream("/Page " + QString::number(item->annotation().Ziel() + 1) + "\n");
PutStream("/View [ /XYZ " + item->annotation().Action() + "]\n");
}
if (item->annotation().ActionType() == Annotation::Action_GoToR_FileRel)
{
QFileInfo fiBase(Spool.fileName());
QString baseDir = fiBase.absolutePath();
PutStream("/Action /GoToR\n");
PutStream("/File (" + Path2Relative(item->annotation().Extern(), baseDir) + ")\n");
PutStream("/Page " + QString::number(item->annotation().Ziel() + 1) + "\n");
PutStream("/View [ /XYZ " + item->annotation().Action() + "]\n");
}
if (item->annotation().ActionType() == Annotation::Action_URI)
{
/* The PDFMark docs say that for URI actions should contain an entry /Subtype /URI
but tests with Ghostscript shows that only /S /URI works. Don't know if that is
an error in the docs or a bug in Ghostscript
PutStream("/Action << /Subtype /URI /URI (" + item->annotation().Extern() + ") >>\n");
*/
PutStream("/Action << /S /URI /URI (" + item->annotation().Extern() + ") >>\n");
}
if (item->annotation().ActionType() == Annotation::Action_GoToR_FileAbs)
{
PutStream("/Action /GoToR\n");
PutStream("/File (" + item->annotation().Extern() + ")\n");
PutStream("/Page " + QString::number(item->annotation().Ziel() + 1) + "\n");
PutStream("/View [ /XYZ " + item->annotation().Action() + "]\n");
}
break;
default:
break;
}
if ((item->annotation().Type() < 2) || (item->annotation().Type() > 9))
PutStream("/Border [ 0 0 0 ]\n");
PutStream("/Title (" + item->itemName().replace(".", "_" ) + ")\n");
PutStream("/ANN pdfmark\n");
}
void PSLib::PS_close()
{
PutStream("%%Trailer\n");
// PutStream("end\n");
PutStream("%%EOF\n");
Spool.close();
}
void PSLib::PS_insert(const QString& i)
{
PutStream(i);
}
void PSLib::PS_Error(const QString& message)
{
ErrorMessage = message;
if (!ScCore->usingGUI())
qDebug("%s", message.toLocal8Bit().data());
}
void PSLib::PS_Error_ImageDataWriteFailure()
{
PS_Error( tr("Failed to write data for an image"));
}
void PSLib::PS_Error_ImageLoadFailure(const QString& fileName)
{
PS_Error( tr("Failed to load an image : %1").arg(fileName) );
}
void PSLib::PS_Error_MaskLoadFailure(const QString& fileName)
{
PS_Error( tr("Failed to load an image mask : %1").arg(fileName) );
}
void PSLib::PS_Error_InsufficientMemory()
{
PS_Error( tr("Insufficient memory for processing an image"));
}
int PSLib::createPS(const QString& outputFileName)
{
bool errorOccured = false;
if (!PS_set_file(outputFileName))
return 1;
std::vector<int> &pageNs = Options.pageNumbers;
bool outputSep = Options.outputSeparations;
QString separationName = Options.separationName;
QStringList separations = Options.allSeparations;
bool Hm = Options.mirrorH;
bool Vm = Options.mirrorV;
bool doClip = Options.doClip;
int sepac;
int pagemult;
if ((outputSep) && (separationName == "All"))
pagemult = separations.count();
else
pagemult = 1;
// QVector<double> dum;
double gx = 0.0;
double gy = 0.0;
double gw = 0.0;
double gh = 0.0;
PS_set_Info("Author", m_Doc->documentInfo().author());
PS_set_Info("Title", m_Doc->documentInfo().title());
if (!Options.useColor)
PS_setGray();
if ((m_Doc->HasCMS) && (ScCore->haveCMS()))
solidTransform = m_Doc->colorEngine.createTransform(m_Doc->DocInputCMYKProf, Format_CMYK_16, m_Doc->DocPrinterProf, Format_CMYK_16, m_Doc->IntentColors, 0);
else
solidTransform = ScColorTransform();
if (ScCore->usingGUI())
{
QString title = QObject::tr("Exporting PostScript File");
if (m_outputFormat == OutputPS)
title = QObject::tr("Printing File");
progressDialog = new MultiProgressDialog(title, CommonStrings::tr_Cancel, m_Doc->scMW());
if (progressDialog)
{
QStringList barNames, barTexts;
barNames << "EMP" << "EP";
barTexts << tr("Processing Master Page:") << tr("Exporting Page:");
QList<bool> barsNumeric;
barsNumeric << true << true;
progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
progressDialog->setOverallTotalSteps(pageNs.size()+m_Doc->MasterPages.count());
progressDialog->setTotalSteps("EMP", m_Doc->MasterPages.count());
progressDialog->setTotalSteps("EP", pageNs.size());
progressDialog->setOverallProgress(0);
progressDialog->setProgress("EMP", 0);
progressDialog->setProgress("EP", 0);
progressDialog->show();
connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
ScQApp->processEvents();
}
}
uint docSelectionCount = m_Doc->m_Selection->count();
if ((m_outputFormat == OutputEPS) && (docSelectionCount != 0))
{
double minx = std::numeric_limits<double>::max();
double miny = std::numeric_limits<double>::max();
double maxx = -std::numeric_limits<double>::max();
double maxy = -std::numeric_limits<double>::max();
for (uint ep = 0; ep < docSelectionCount; ++ep)
{
PageItem* currItem = m_Doc->m_Selection->itemAt(ep);
double lw = currItem->lineWidth() / 2.0;
if (currItem->rotation() != 0)
{
FPointArray pb;
pb.resize(0);
pb.addPoint(FPoint(currItem->xPos() - lw, currItem->yPos() - lw));
pb.addPoint(FPoint(currItem->width() + lw * 2.0, -lw, currItem->xPos() - lw, currItem->yPos() - lw, currItem->rotation(), 1.0, 1.0));
pb.addPoint(FPoint(currItem->width() + lw * 2.0, currItem->height() + lw * 2.0, currItem->xPos() - lw, currItem->yPos() - lw, currItem->rotation(), 1.0, 1.0));
pb.addPoint(FPoint(-lw, currItem->height() + lw * 2.0, currItem->xPos() - lw, currItem->yPos() - lw, currItem->rotation(), 1.0, 1.0));
for (uint pc = 0; pc < 4; ++pc)
{
minx = qMin(minx, pb.point(pc).x());
miny = qMin(miny, pb.point(pc).y());
maxx = qMax(maxx, pb.point(pc).x());
maxy = qMax(maxy, pb.point(pc).y());
}
}
else
{
minx = qMin(minx, currItem->xPos() - lw);
miny = qMin(miny, currItem->yPos() - lw);
maxx = qMax(maxx, currItem->xPos() - lw + currItem->width() + lw * 2.0);
maxy = qMax(maxy, currItem->yPos() - lw + currItem->height()+ lw * 2.0);
}
}
gx = minx;
gy = miny;
gw = maxx - minx;
gh = maxy - miny;
int pgNum = pageNs[0] - 1;
gx -= m_Doc->Pages->at(pgNum)->xOffset();
gy -= m_Doc->Pages->at(pgNum)->yOffset();
errorOccured = !PS_begin_doc(gx, m_Doc->pageHeight() - (gy + gh), gx + gw, m_Doc->pageHeight() - gy, 1 * pagemult);
}
else
{
double maxWidth = 0.0;
double maxHeight = 0.0;
for (size_t i = 0; i < pageNs.size(); ++i)
{
int pgNum = pageNs[i] - 1;
maxWidth = qMax(m_Doc->Pages->at(pgNum)->width(), maxWidth);
maxHeight = qMax(m_Doc->Pages->at(pgNum)->height(), maxHeight);
}
errorOccured = !PS_begin_doc(0.0, 0.0, maxWidth, maxHeight, pageNs.size() * pagemult);
}
sepac = 0;
uint aa = 0;
uint a;
while (aa < pageNs.size() && !abortExport && !errorOccured)
{
if (progressDialog)
{
progressDialog->setProgress("EP", aa);
progressDialog->setOverallProgress(aa + m_Doc->MasterPages.count());
ScQApp->processEvents();
}
a = pageNs[aa]-1;
ScPage* page = m_Doc->Pages->at(a);
if ((m_outputFormat == OutputEPS) && (m_Doc->m_Selection->count() != 0))
{
MarginStruct Ma;
Ma.setLeft(gx);
Ma.setTop(gy);
Ma.setBottom(page->height() - (gy + gh));
Ma.setRight(page->width() - (gx + gw));
PS_begin_page(page, &Ma, true);
}
else
PS_begin_page(page, &page->Margins, doClip);
if (Hm)
{
PS_translate(page->width(), 0);
PS_scale(-1, 1);
}
if (Vm)
{
PS_translate(0, page->height());
PS_scale(1, -1);
}
if (outputSep)
{
if (separationName == "Black")
PS_plate(0);
else if (separationName == "Cyan")
PS_plate(1);
else if (separationName == "Magenta")
PS_plate(2);
else if (separationName == "Yellow")
PS_plate(3);
else if (separationName == "All")
PS_plate(sepac, separations[sepac]);
else
PS_plate(4, separationName);
}
ScLayer ll;
ll.isPrintable = false;
for (int lam = 0; lam < m_Doc->Layers.count() && !abortExport && !errorOccured; ++lam)
{
m_Doc->Layers.levelToLayer(ll, lam);
if (!ll.isPrintable)
continue;
if (!page->masterPageNameEmpty() && !abortExport && !errorOccured)
{
errorOccured |= !ProcessMasterPageLayer(page, ll, a + 1);
}
if (!abortExport && !errorOccured)
{
errorOccured |= !ProcessPageLayer(page, ll, a + 1);
}
}
if (!abortExport && !errorOccured)
PS_end_page();
if (outputSep)
{
if (separationName != "All")
aa++;
else
{
if (sepac == static_cast<int>(separations.count() - 1))
{
aa++;
sepac = 0;
}
else
sepac++;
}
}
else
aa++;
}
PS_close();
if (progressDialog)
progressDialog->close();
if (errorOccured)
return 1;
if (abortExport)
return 2; //CB Lets leave 1 for general error condition
return 0;
}
bool PSLib::ProcessItem(ScPage* page, PageItem* item, uint PNr, bool master, bool embedded, bool useTemplate)
{
double h, s, v, k;
QVector<double> dum;
if (!item->printEnabled())
return true;
fillRule = true;
PS_save();
if (item->doOverprint)
{
PutStream("true setoverprint\n");
PutStream("true setoverprintmode\n");
}
if (item->fillColor() != CommonStrings::None)
{
SetColor(item->fillColor(), item->fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h, s, v, k);
}
if (item->lineColor() != CommonStrings::None)
{
SetColor(item->lineColor(), item->lineShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
}
PS_setlinewidth(item->lineWidth());
PS_setcapjoin(item->PLineEnd, item->PLineJoin);
PS_setdash(item->PLineArt, item->DashOffset, item->DashValues);
if (!embedded)
{
PS_translate(item->xPos() - page->xOffset(), page->height() - (item->yPos() - page->yOffset()));
}
if (item->rotation() != 0)
PS_rotate(-item->rotation());
switch (item->itemType())
{
case PageItem::ImageFrame:
case PageItem::LatexFrame:
if (master)
break;
if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
SetClipPath(item->PoLine);
PS_closepath();
if (item->GrType == Gradient_Hatch)
PS_HatchFill(item);
else if ((item->GrType != 0) && (!master))
HandleGradientFillStroke(item, false);
else
putColor(item->fillColor(), item->fillShade(), true);
PS_newpath();
}
PS_save();
SetPathAndClip(item->PoLine, true);
if (item->imageFlippedH())
{
PS_translate(item->width(), 0);
PS_scale(-1, 1);
}
if (item->imageFlippedV())
{
PS_translate(0, -item->height());
PS_scale(1, -1);
}
if (!item->imageClip.empty())
SetPathAndClip(item->imageClip, true);
if ((item->imageIsAvailable) && (!item->Pfile.isEmpty()))
{
bool imageOk = false;
PS_translate(0, -item->BBoxH * item->imageYScale());
if ((m_optimization == OptimizeSize) && (((!page->pageNameEmpty()) && !Options.outputSeparations && Options.useColor) || useTemplate))
imageOk = PS_image(item, item->imageXOffset(), -item->imageYOffset(), item->Pfile, item->imageXScale(), item->imageYScale(), item->ImageProfile, item->UseEmbedded, item->itemName());
else
imageOk = PS_image(item, item->imageXOffset(), -item->imageYOffset(), item->Pfile, item->imageXScale(), item->imageYScale(), item->ImageProfile, item->UseEmbedded);
if (!imageOk) return false;
}
PS_restore();
if (((item->lineColor() != CommonStrings::None) || (!item->NamedLStyle.isEmpty()) || (!item->strokePattern().isEmpty()) || (item->GrTypeStroke > 0)))
{
if (item->NamedLStyle.isEmpty()) // && (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if ((strokePattern) && (item->patternStrokePath))
{
QPainterPath path = item->PoLine.toQPainterPath(false);
HandleBrushPattern(item, path, page, PNr, master);
}
else
{
PS_setlinewidth(item->lineWidth());
PS_setcapjoin(item->PLineEnd, item->PLineJoin);
PS_setdash(item->PLineArt, item->DashOffset, item->DashValues);
SetClipPath(item->PoLine);
PS_closepath();
if (strokePattern)
HandleStrokePattern(item);
else if (item->GrTypeStroke > 0)
HandleGradientFillStroke(item);
else if (item->lineColor() != CommonStrings::None)
{
SetColor(item->lineColor(), item->lineShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
putColor(item->lineColor(), item->lineShade(), false);
}
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) // && (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(item->PoLine);
PS_closepath();
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
}
break;
case PageItem::TextFrame:
if (master)
break;
if ((item->isBookmark || item->isAnnotation()) && (!Options.includePDFMarks))
break;
if (item->isBookmark)
{
QString bm = "";
QString cc;
for (int d = 0; d < item->itemText.length(); ++d)
{
if ((item->itemText.text(d) == QChar(13)) || (item->itemText.text(d) == QChar(10)) || (item->itemText.text(d) == QChar(28)))
break;
bm += "\\" + cc.setNum(qMax(item->itemText.text(d).unicode(), (ushort) 32), 8);
}
PDF_Bookmark(bm, page->pageNr()+1);
}
if (item->isAnnotation())
{
if ((item->annotation().Type() == 0) || (item->annotation().Type() == 1) || (item->annotation().Type() == Annotation::Text) || (item->annotation().Type() == Annotation::Link))
{
QString bm = "";
QString cc;
for (int d = 0; d < item->itemText.length(); ++d)
{
bm += "\\" + cc.setNum(qMax(item->itemText.text(d).unicode(), (ushort) 32), 8);
}
PDF_Annotation(item, bm, 0, 0, item->width(), -item->height());
}
break;
}
if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
SetClipPath(item->PoLine);
PS_closepath();
if (item->GrType == Gradient_Hatch)
PS_HatchFill(item);
else if ((item->GrType != 0) && (!master))
HandleGradientFillStroke(item, false);
else
putColor(item->fillColor(), item->fillShade(), true);
}
if (item->imageFlippedH())
{
PS_translate(item->width(), 0);
PS_scale(-1, 1);
}
if (item->imageFlippedV())
{
PS_translate(0, -item->height());
PS_scale(1, -1);
}
if (item->itemText.length() != 0)
setTextSt(item, PNr - 1, page, master);
if (((item->lineColor() != CommonStrings::None) || (!item->NamedLStyle.isEmpty()) || (!item->strokePattern().isEmpty()) || (item->GrTypeStroke > 0)))
{
PS_setlinewidth(item->lineWidth());
PS_setcapjoin(item->PLineEnd, item->PLineJoin);
PS_setdash(item->PLineArt, item->DashOffset, item->DashValues);
if (item->NamedLStyle.isEmpty()) // && (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if ((strokePattern) && (item->patternStrokePath))
{
QPainterPath path = item->PoLine.toQPainterPath(false);
HandleBrushPattern(item, path, page, PNr, master);
}
else
{
SetClipPath(item->PoLine);
PS_closepath();
if (strokePattern)
HandleStrokePattern(item);
else if (item->GrTypeStroke > 0)
HandleGradientFillStroke(item);
else if (item->lineColor() != CommonStrings::None)
{
SetColor(item->lineColor(), item->lineShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
putColor(item->lineColor(), item->lineShade(), false);
}
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(item->PoLine);
PS_closepath();
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
}
break;
case PageItem::Line:
if (item->NamedLStyle.isEmpty()) // && (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if (strokePattern)
{
if (item->patternStrokePath)
{
QPainterPath guidePath;
guidePath.moveTo(0, 0);
guidePath.lineTo(item->width(), 0);
HandleBrushPattern(item, guidePath, page, PNr, master);
}
else
{
PS_moveto(0, 0);
PS_lineto(item->width(), 0);
HandleStrokePattern(item);
}
}
else if (item->GrTypeStroke > 0)
{
PS_moveto(0, 0);
PS_lineto(item->width(), 0);
HandleGradientFillStroke(item);
}
else if (item->lineColor() != CommonStrings::None)
{
PS_moveto(0, 0);
PS_lineto(item->width(), 0);
putColor(item->lineColor(), item->lineShade(), false);
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
PS_moveto(0, 0);
PS_lineto(item->width(), 0);
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
if (item->startArrowIndex() != 0)
{
QTransform arrowTrans;
arrowTrans.scale(-1,1);
arrowTrans.scale(item->startArrowScale() / 100.0, item->startArrowScale() / 100.0);
drawArrow(item, arrowTrans, item->startArrowIndex());
}
if (item->endArrowIndex() != 0)
{
QTransform arrowTrans;
arrowTrans.translate(item->width(), 0);
arrowTrans.scale(item->endArrowScale() / 100.0, item->endArrowScale() / 100.0);
drawArrow(item, arrowTrans, item->endArrowIndex());
}
break;
/* OBSOLETE CR 2005-02-06
case 1:
case 3:
*/
case PageItem::ItemType1:
case PageItem::ItemType3:
case PageItem::Polygon:
case PageItem::RegularPolygon:
case PageItem::Arc:
if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
SetClipPath(item->PoLine);
PS_closepath();
fillRule = item->fillRule;
if (item->GrType == Gradient_Hatch)
PS_HatchFill(item);
else if (item->GrType != 0)
HandleGradientFillStroke(item, false);
else
putColor(item->fillColor(), item->fillShade(), true);
}
if ((item->lineColor() != CommonStrings::None) || (!item->NamedLStyle.isEmpty()) || (!item->strokePattern().isEmpty()) || (item->GrTypeStroke > 0))
{
if (item->NamedLStyle.isEmpty()) //&& (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if (strokePattern && (item->patternStrokePath))
{
QPainterPath path = item->PoLine.toQPainterPath(false);
HandleBrushPattern(item, path, page, PNr, master);
}
else
{
SetClipPath(item->PoLine);
PS_closepath();
if (strokePattern)
HandleStrokePattern(item);
else if (item->GrTypeStroke > 0)
HandleGradientFillStroke(item);
else if (item->lineColor() != CommonStrings::None)
putColor(item->lineColor(), item->lineShade(), false);
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(item->PoLine);
PS_closepath();
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
}
break;
case PageItem::PolyLine:
case PageItem::Spiral:
if ((item->fillColor() != CommonStrings::None) || (item->GrType != 0))
{
SetClipPath(item->PoLine);
PS_closepath();
fillRule = item->fillRule;
if (item->GrType == Gradient_Hatch)
PS_HatchFill(item);
else if (item->GrType != 0)
HandleGradientFillStroke(item, false);
else
putColor(item->fillColor(), item->fillShade(), true);
PS_newpath();
}
if ((item->lineColor() != CommonStrings::None) || (!item->NamedLStyle.isEmpty()) || (!item->strokePattern().isEmpty()) || (item->GrTypeStroke > 0))
{
if (item->NamedLStyle.isEmpty()) //&& (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if (strokePattern && (item->patternStrokePath))
{
QPainterPath path = item->PoLine.toQPainterPath(false);
HandleBrushPattern(item, path, page, PNr, master);
}
else
{
SetClipPath(item->PoLine, false);
if (strokePattern)
HandleStrokePattern(item);
else if (item->GrTypeStroke > 0)
HandleGradientFillStroke(item);
else if (item->lineColor() != CommonStrings::None)
putColor(item->lineColor(), item->lineShade(), false);
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(item->PoLine, false);
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
}
if (item->startArrowIndex() != 0)
{
FPoint Start = item->PoLine.point(0);
for (int xx = 1; xx < item->PoLine.size(); xx += 2)
{
FPoint Vector = item->PoLine.point(xx);
if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
{
double r = atan2(Start.y() - Vector.y(), Start.x() - Vector.x()) * (180.0 / M_PI);
QTransform arrowTrans;
arrowTrans.translate(Start.x(), Start.y());
arrowTrans.rotate(r);
arrowTrans.scale(item->startArrowScale() / 100.0, item->startArrowScale() / 100.0);
drawArrow(item, arrowTrans, item->startArrowIndex());
break;
}
}
}
if (item->endArrowIndex() != 0)
{
FPoint End = item->PoLine.point(item->PoLine.size() - 2);
for (uint xx = item->PoLine.size() - 1; xx > 0; xx -= 2)
{
FPoint Vector = item->PoLine.point(xx);
if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
{
double r = atan2(End.y() - Vector.y(),End.x() - Vector.x())*(180.0/M_PI);
QTransform arrowTrans;
arrowTrans.translate(End.x(), End.y());
arrowTrans.rotate(r);
arrowTrans.scale(item->endArrowScale() / 100.0, item->endArrowScale() / 100.0);
drawArrow(item, arrowTrans, item->endArrowIndex());
break;
}
}
}
break;
case PageItem::PathText:
if (master)
break;
if (item->PoShow)
{
if (item->PoLine.size() > 3)
{
PS_save();
if (item->NamedLStyle.isEmpty()) //&& (item->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(item->strokePattern());
if (strokePattern && (item->patternStrokePath))
{
QPainterPath path = item->PoLine.toQPainterPath(false);
HandleBrushPattern(item, path, page, PNr, master);
}
else
{
SetClipPath(item->PoLine, false);
if (strokePattern)
HandleStrokePattern(item);
else if (item->GrTypeStroke > 0)
HandleGradientFillStroke(item);
else if (item->lineColor() != CommonStrings::None)
putColor(item->lineColor(), item->lineShade(), false);
}
}
else
{
multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(item->PoLine, false);
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
PS_restore();
}
}
if (item->itemText.length() != 0)
setTextSt(item, PNr-1, page, master);
break;
case PageItem::Symbol:
if (m_Doc->docPatterns.contains(item->pattern()))
{
ScPattern pat = m_Doc->docPatterns[item->pattern()];
PS_save();
SetPathAndClip(item->PoLine, item->fillRule);
if (item->imageFlippedH())
{
PS_translate(item->width(), 0);
PS_scale(-1, 1);
}
if (item->imageFlippedV())
{
PS_translate(0, -item->height());
PS_scale(1, -1);
}
PS_scale(item->width() / pat.width, item->height() / pat.height);
PS_translate(0, -item->height());
// PS_translate(pat.items.at(0)->gXpos, -pat.items.at(0)->gYpos);
for (int em = 0; em < pat.items.count(); ++em)
{
PageItem* embed = pat.items.at(em);
PS_save();
PS_translate(embed->gXpos, item->height() - embed->gYpos);
ProcessItem(page, embed, PNr, master, true, useTemplate);
PS_restore();
}
PS_restore();
}
break;
case PageItem::Group:
if (master)
break;
PS_save();
if (item->groupClipping())
SetPathAndClip(item->PoLine, item->fillRule);
if (item->imageFlippedH())
{
PS_translate(item->width(), 0);
PS_scale(-1, 1);
}
if (item->imageFlippedV())
{
PS_translate(0, -item->height());
PS_scale(1, -1);
}
PS_scale(item->width() / item->groupWidth, item->height() / item->groupHeight);
PS_translate(0, -item->height());
for (int em = 0; em < item->groupItemList.count(); ++em)
{
PageItem* embed = item->groupItemList.at(em);
PS_save();
PS_translate(embed->gXpos, item->height() - embed->gYpos);
ProcessItem(page, embed, PNr, master, true, useTemplate);
PS_restore();
}
PS_restore();
break;
case PageItem::Table:
if (master)
break;
PS_save();
PS_translate(item->asTable()->gridOffset().x(), -item->asTable()->gridOffset().y());
// Paint table fill.
if (item->asTable()->fillColor() != CommonStrings::None)
{
int lastCol = item->asTable()->columns() - 1;
int lastRow = item->asTable()->rows() - 1;
double x = item->asTable()->columnPosition(0);
double y = item->asTable()->rowPosition(0);
double width = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol) - x;
double height = item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow) - y;
putColorNoDraw(item->asTable()->fillColor(), item->asTable()->fillShade());
PutStream("0 0 " + ToStr(width) + " " + ToStr(-height) + " rectfill\n");
}
// Pass 1: Paint cell fills.
for (int row = 0; row < item->asTable()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < item->asTable()->columns(); col += colSpan)
{
TableCell cell = item->asTable()->cellAt(row, col);
if (row == cell.row())
{
QString colorName = cell.fillColor();
if (colorName != CommonStrings::None)
{
PS_save();
putColorNoDraw(colorName, cell.fillShade());
int row = cell.row();
int col = cell.column();
int lastRow = row + cell.rowSpan() - 1;
int lastCol = col + cell.columnSpan() - 1;
double x = item->asTable()->columnPosition(col);
double y = item->asTable()->rowPosition(row);
double width = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol) - x;
double height = item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow) - y;
PutStream(ToStr(x) + " " + ToStr(-y) + " " + ToStr(width) + " " + ToStr(-height) + " rectfill\n");
PS_restore();
}
}
colSpan = cell.columnSpan();
}
}
// Pass 2: Paint vertical borders.
for (int row = 0; row < item->asTable()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < item->asTable()->columns(); col += colSpan)
{
TableCell cell = item->asTable()->cellAt(row, col);
if (row == cell.row())
{
const int lastRow = cell.row() + cell.rowSpan() - 1;
const int lastCol = cell.column() + cell.columnSpan() - 1;
const double borderX = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol);
QPointF start(borderX, 0.0);
QPointF end(borderX, 0.0);
QPointF startOffsetFactors, endOffsetFactors;
int startRow, endRow;
for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
{
TableCell rightCell = item->asTable()->cellAt(row, lastCol + 1);
startRow = qMax(cell.row(), rightCell.row());
endRow = qMin(lastRow, rightCell.isValid() ? rightCell.row() + rightCell.rowSpan() - 1 : lastRow);
TableCell topLeftCell = item->asTable()->cellAt(startRow - 1, lastCol);
TableCell topRightCell = item->asTable()->cellAt(startRow - 1, lastCol + 1);
TableCell bottomRightCell = item->asTable()->cellAt(endRow + 1, lastCol + 1);
TableCell bottomLeftCell = item->asTable()->cellAt(endRow + 1, lastCol);
TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
resolveBordersVertical(topLeftCell, topRightCell, cell, rightCell, bottomLeftCell, bottomRightCell,
&topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, item->asTable());
if (border.isNull())
continue; // Quit early if the border to paint is null.
start.setY(item->asTable()->rowPosition(startRow));
end.setY((item->asTable()->rowPosition(endRow) + item->asTable()->rowHeight(endRow)));
joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors);
}
if (col == 0)
{
const int lastRow = cell.row() + cell.rowSpan() - 1;
const int firstCol = cell.column();
const double borderX = item->asTable()->columnPosition(firstCol);
QPointF start(borderX, 0.0);
QPointF end(borderX, 0.0);
QPointF startOffsetFactors, endOffsetFactors;
int startRow, endRow;
for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
{
TableCell leftCell = item->asTable()->cellAt(row, firstCol - 1);
startRow = qMax(cell.row(), leftCell.row());
endRow = qMin(lastRow, leftCell.isValid() ? leftCell.row() + leftCell.rowSpan() - 1 : lastRow);
TableCell topLeftCell = item->asTable()->cellAt(startRow - 1, firstCol - 1);
TableCell topRightCell = item->asTable()->cellAt(startRow - 1, firstCol);
TableCell bottomRightCell = item->asTable()->cellAt(lastRow + 1, firstCol);
TableCell bottomLeftCell = item->asTable()->cellAt(lastRow + 1, firstCol - 1);
TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
resolveBordersVertical(topLeftCell, topRightCell, leftCell, cell, bottomLeftCell, bottomRightCell,
&topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, item->asTable());
if (border.isNull())
continue; // Quit early if the border to paint is null.
start.setY(item->asTable()->rowPosition(startRow));
end.setY((item->asTable()->rowPosition(endRow) + item->asTable()->rowHeight(endRow)));
joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors);
}
}
}
colSpan = cell.columnSpan();
}
}
// Pass 3: Paint horizontal borders.
for (int row = 0; row < item->asTable()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < item->asTable()->columns(); col += colSpan)
{
TableCell cell = item->asTable()->cellAt(row, col);
if (row == cell.row())
{
const int lastRow = cell.row() + cell.rowSpan() - 1;
const int lastCol = cell.column() + cell.columnSpan() - 1;
const double borderY = (item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow));
QPointF start(0.0, borderY);
QPointF end(0.0, borderY);
QPointF startOffsetFactors, endOffsetFactors;
int startCol, endCol;
for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
{
TableCell bottomCell = item->asTable()->cellAt(lastRow + 1, col);
startCol = qMax(cell.column(), bottomCell.column());
endCol = qMin(lastCol, bottomCell.isValid() ? bottomCell.column() + bottomCell.columnSpan() - 1 : lastCol);
TableCell topLeftCell = item->asTable()->cellAt(lastRow, startCol - 1);
TableCell topRightCell = item->asTable()->cellAt(lastRow, endCol + 1);
TableCell bottomRightCell = item->asTable()->cellAt(lastRow + 1, endCol + 1);
TableCell bottomLeftCell = item->asTable()->cellAt(lastRow + 1, startCol - 1);
TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
resolveBordersHorizontal(topLeftCell, cell, topRightCell, bottomLeftCell, bottomCell,
bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, item->asTable());
if (border.isNull())
continue; // Quit early if the border is null.
start.setX(item->asTable()->columnPosition(startCol));
end.setX(item->asTable()->columnPosition(endCol) + item->asTable()->columnWidth(endCol));
joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors);
}
if (row == 0)
{
const int firstRow = cell.row();
const int lastCol = cell.column() + cell.columnSpan() - 1;
const double borderY = item->asTable()->rowPosition(firstRow);
QPointF start(0.0, borderY);
QPointF end(0.0, borderY);
QPointF startOffsetFactors, endOffsetFactors;
int startCol, endCol;
for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
{
TableCell topCell = item->asTable()->cellAt(firstRow - 1, col);
startCol = qMax(cell.column(), topCell.column());
endCol = qMin(lastCol, topCell.isValid() ? topCell.column() + topCell.columnSpan() - 1 : lastCol);
TableCell topLeftCell = item->asTable()->cellAt(firstRow - 1, startCol - 1);
TableCell topRightCell = item->asTable()->cellAt(firstRow - 1, endCol + 1);
TableCell bottomRightCell = item->asTable()->cellAt(firstRow, endCol + 1);
TableCell bottomLeftCell = item->asTable()->cellAt(firstRow, startCol - 1);
TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
resolveBordersHorizontal(topLeftCell, topCell, topRightCell, bottomLeftCell, cell,
bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, item->asTable());
if (border.isNull())
continue; // Quit early if the border is null.
start.setX(item->asTable()->columnPosition(startCol));
end.setX(item->asTable()->columnPosition(endCol) + item->asTable()->columnWidth(endCol));
joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors);
}
}
}
colSpan = cell.columnSpan();
}
}
// Pass 4: Paint cell content.
for (int row = 0; row < item->asTable()->rows(); ++row)
{
for (int col = 0; col < item->asTable()->columns(); col ++)
{
TableCell cell = item->asTable()->cellAt(row, col);
if (cell.row() == row && cell.column() == col)
{
PageItem* textFrame = cell.textFrame();
PS_save();
PS_translate(cell.contentRect().x(), -cell.contentRect().y());
ProcessItem(page, textFrame, PNr, master, true);
PS_restore();
}
}
}
PS_restore();
break;
default:
break;
}
PS_restore();
return true;
}
void PSLib::paintBorder(const TableBorder& border, const QPointF& start, const QPointF& end, const QPointF& startOffsetFactors, const QPointF& endOffsetFactors)
{
PS_save();
QPointF lineStart, lineEnd;
QVector<double> DashValues;
for (const TableBorderLine& line : border.borderLines())
{
if (line.color() == CommonStrings::None)
continue;
lineStart.setX(start.x() + line.width() * startOffsetFactors.x());
lineStart.setY(start.y() + line.width() * startOffsetFactors.y());
lineEnd.setX(end.x() + line.width() * endOffsetFactors.x());
lineEnd.setY(end.y() + line.width() * endOffsetFactors.y());
PS_moveto(lineStart.x(), -lineStart.y());
PS_lineto(lineEnd.x(), -lineEnd.y());
PS_setlinewidth(line.width());
getDashArray(line.style(), qMax(line.width(), 1.0), DashValues);
PS_setdash(line.style(), 0, DashValues);
double h, s, v, k;
SetColor(line.color(), line.shade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setcapjoin(Qt::FlatCap, Qt::MiterJoin);
putColor(line.color(), line.shade(), false);
}
PS_restore();
}
void PSLib::ProcessPage(ScPage* page, uint PNr)
{
PageItem *item;
QList<PageItem*> pageItems = (page->pageNameEmpty()) ? m_Doc->DocItems : m_Doc->MasterItems;
ScLayer ll;
ll.isPrintable = false;
ll.ID = 0;
for (int layerLevel = 0; layerLevel < m_Doc->Layers.count(); ++layerLevel)
{
m_Doc->Layers.levelToLayer(ll, layerLevel);
if (!ll.isPrintable)
continue;
for (int i = 0; i < pageItems.count() && !abortExport; ++i)
{
item = pageItems.at(i);
if (progressDialog)
ScQApp->processEvents();
if (item->m_layerID != ll.ID)
continue;
if ((!page->pageNameEmpty()) && (item->isTextContainer()))
continue;
if ((!page->pageNameEmpty()) && (item->isImageFrame()) && ((Options.outputSeparations) || (!Options.useColor)))
continue;
//if ((!Art) && (view->SelItem.count() != 0) && (!item->Select))
if ((m_outputFormat == OutputEPS) && (!item->isSelected()) && (m_Doc->m_Selection->count() != 0))
continue;
double bLeft, bRight, bBottom, bTop;
GetBleeds(page, bLeft, bRight, bBottom, bTop);
double x1 = page->xOffset() - bLeft;
double y1 = page->yOffset() - bTop;
double w1 = page->width() + bLeft + bRight;
double h1 = page->height() + bBottom + bTop;
double lw = item->visualLineWidth();
double x2 = item->BoundingX - lw / 2.0;
double y2 = item->BoundingY - lw / 2.0;
double w2 = qMax(item->BoundingW + lw, 1.0);
double h2 = qMax(item->BoundingH + lw, 1.0);
if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x1, y1, w1, h1)))
continue;
if (item->ChangedMasterItem)
continue;
if ((!page->pageNameEmpty()) && (item->OwnPage != page->pageNr()) && (item->OwnPage != -1))
continue;
ProcessItem(page, item, PNr, false);
}
}
}
bool PSLib::ProcessMasterPageLayer(ScPage* page, ScLayer& layer, uint PNr)
{
bool success = true;
double h, s, v, k;
QVector<double> dum;
ScPage* mPage = m_Doc->MasterPages.at(m_Doc->MasterNames[page->masterPageName()]);
if (layer.isPrintable)
{
for (int am = 0; am < page->FromMaster.count() && !abortExport; ++am)
{
PageItem *ite = page->FromMaster.at(am);
if (progressDialog)
ScQApp->processEvents();
if ((ite->m_layerID != layer.ID) || (!ite->printEnabled()))
continue;
if (!ite->isTextContainer())
{
int mpIndex = m_Doc->MasterNames[page->masterPageName()];
PS_UseTemplate(QString("mp_obj_%1_%2").arg(mpIndex).arg(qHash(ite)));
}
else if (!ite->isTextFrame())
{
PS_save();
// JG : replace what seems mostly duplicate code by corresponding function call (#3936)
success &= ProcessItem(mPage, ite, PNr, false, false, true);
PS_restore();
}
else // if (ite->isTextFrame())
{
PS_save();
if (ite->doOverprint)
{
PutStream("true setoverprint\n");
PutStream("true setoverprintmode\n");
}
if (ite->fillColor() != CommonStrings::None)
{
SetColor(ite->fillColor(), ite->fillShade(), &h, &s, &v, &k);
PS_setcmykcolor_fill(h, s, v, k);
}
PS_translate(ite->xPos() - mPage->xOffset(), mPage->height() - (ite->yPos() - mPage->yOffset()));
if (ite->rotation() != 0)
PS_rotate(-ite->rotation());
if ((ite->fillColor() != CommonStrings::None) || (ite->GrType != 0))
{
SetClipPath(ite->PoLine);
PS_closepath();
if (ite->GrType == Gradient_Hatch)
PS_HatchFill(ite);
else if (ite->GrType != 0)
HandleGradientFillStroke(ite, false);
else
putColor(ite->fillColor(), ite->fillShade(), true);
}
if (ite->imageFlippedH())
{
PS_translate(ite->width(), 0);
PS_scale(-1, 1);
}
if (ite->imageFlippedV())
{
PS_translate(0, -ite->height());
PS_scale(1, -1);
}
if (ite->itemText.length() != 0)
setTextSt(ite, PNr - 1, mPage, true);
if (((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()) || (!ite->strokePattern().isEmpty()) || (ite->GrTypeStroke > 0)))
{
PS_setlinewidth(ite->lineWidth());
PS_setcapjoin(ite->PLineEnd, ite->PLineJoin);
PS_setdash(ite->PLineArt, ite->DashOffset, ite->DashValues);
if (ite->NamedLStyle.isEmpty()) // && (ite->lineWidth() != 0.0))
{
ScPattern* strokePattern = m_Doc->checkedPattern(ite->strokePattern());
if (strokePattern && (ite->patternStrokePath))
{
QPainterPath path = ite->PoLine.toQPainterPath(false);
HandleBrushPattern(ite, path, page, PNr, true);
}
else
{
SetClipPath(ite->PoLine);
PS_closepath();
if (strokePattern)
HandleStrokePattern(ite);
else if (ite->GrTypeStroke > 0)
HandleGradientFillStroke(ite);
else if (ite->lineColor() != CommonStrings::None)
{
SetColor(ite->lineColor(), ite->lineShade(), &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
putColor(ite->lineColor(), ite->lineShade(), false);
}
}
}
else
{
multiLine ml = m_Doc->docLineStyles[ite->NamedLStyle];
for (int it = ml.size() - 1; it > -1; it--)
{
if (ml[it].Color != CommonStrings::None) //&& (ml[it].Width != 0))
{
SetColor(ml[it].Color, ml[it].Shade, &h, &s, &v, &k);
PS_setcmykcolor_stroke(h, s, v, k);
PS_setlinewidth(ml[it].Width);
PS_setcapjoin(static_cast<Qt::PenCapStyle>(ml[it].LineEnd), static_cast<Qt::PenJoinStyle>(ml[it].LineJoin));
PS_setdash(static_cast<Qt::PenStyle>(ml[it].Dash), 0, dum);
SetClipPath(ite->PoLine);
PS_closepath();
putColor(ml[it].Color, ml[it].Shade, false);
}
}
}
}
PS_restore();
}
if (!success)
break;
}
}
return success;
}
bool PSLib::ProcessPageLayer(ScPage* page, ScLayer& layer, uint PNr)
{
bool success = true;
if (!layer.isPrintable || abortExport)
return true;
QList<PageItem*> items;
items = (page->pageNameEmpty()) ? m_Doc->DocItems : m_Doc->MasterItems;
for (int i = 0; i < items.count() && !abortExport; ++i)
{
PageItem *item = items.at(i);
if (progressDialog)
ScQApp->processEvents();
if (item->m_layerID != layer.ID)
continue;
if ((!page->pageNameEmpty()) && (item->isTextContainer()))
continue;
if ((!page->pageNameEmpty()) && (item->isImageFrame()) && ((Options.outputSeparations) || (!Options.useColor)))
continue;
//if ((!Art) && (view->SelItem.count() != 0) && (!item->Select))
if ((m_outputFormat == OutputEPS) && (!item->isSelected()) && (m_Doc->m_Selection->count() != 0))
continue;
double bLeft, bRight, bBottom, bTop;
GetBleeds(page, bLeft, bRight, bBottom, bTop);
double x1 = page->xOffset() - bLeft;
double y1 = page->yOffset() - bTop;
double w1 = page->width() + bLeft + bRight;
double h1 = page->height() + bBottom + bTop;
double lw = item->visualLineWidth();
double x2 = item->BoundingX - lw / 2.0;
double y2 = item->BoundingY - lw / 2.0;
double w2 = qMax(item->BoundingW + lw, 1.0);
double h2 = qMax(item->BoundingH + lw, 1.0);
if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x1, y1, w1, h1)))
continue;
if (item->ChangedMasterItem)
continue;
if ((!page->pageNameEmpty()) && (item->OwnPage != page->pageNr()) && (item->OwnPage != -1))
continue;
success &= ProcessItem(page, item, PNr, false);
if (!success)
break;
}
return success;
}
void PSLib::HandleBrushPattern(PageItem *item, QPainterPath &path, ScPage* page, uint PNr, bool master)
{
ScPattern pat = m_Doc->docPatterns[item->strokePattern()];
double pLen = path.length() - ((pat.width / 2.0) * (item->patternStrokeScaleX / 100.0));
double adv = pat.width * item->patternStrokeScaleX / 100.0 * item->patternStrokeSpace;
double xpos = item->patternStrokeOffsetX * item->patternStrokeScaleX / 100.0;
while (xpos < pLen)
{
double currPerc = path.percentAtLength(xpos);
double currAngle = path.angleAtPercent(currPerc);
if (currAngle <= 180.0)
currAngle *= -1.0;
else
currAngle = 360.0 - currAngle;
QPointF currPoint = path.pointAtPercent(currPerc);
PS_save();
PS_translate(currPoint.x(), -currPoint.y());
PS_rotate(-currAngle);
QTransform trans;
trans.translate(0.0, -item->patternStrokeOffsetY);
trans.rotate(-item->patternStrokeRotation);
trans.shear(item->patternStrokeSkewX, -item->patternStrokeSkewY);
trans.scale(item->patternStrokeScaleX / 100.0, item->patternStrokeScaleY / 100.0);
trans.translate(-pat.width / 2.0, -pat.height / 2.0);
if (item->patternStrokeMirrorX)
{
trans.translate(pat.width, 0);
trans.scale(-1, 1);
}
if (item->patternStrokeMirrorY)
{
trans.translate(0, pat.height);
trans.scale(1, -1);
}
PutStream( MatrixToStr(trans.m11(), trans.m12(), trans.m21(), trans.m22(), trans.dx(), trans.dy()) + " concat\n");
for (int em = 0; em < pat.items.count(); ++em)
{
PageItem* embedded = pat.items.at(em);
PS_save();
PS_translate(embedded->gXpos, embedded->gHeight - embedded->gYpos);
ProcessItem(page, embedded, PNr, master, true);
PS_restore();
}
xpos += adv;
PS_restore();
}
}
void PSLib::HandleStrokePattern(PageItem *item)
{
ScPattern *pat;
QTransform patternMatrix;
double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY, patternSpace;
pat = &m_Doc->docPatterns[item->strokePattern()];
uint patHash = qHash(item->strokePattern());
item->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY, patternSpace);
patternMatrix.translate(-item->lineWidth() / 2.0, item->lineWidth() / 2.0);
patternMatrix.translate(patternOffsetX, -patternOffsetY);
patternMatrix.rotate(-patternRotation);
patternMatrix.shear(patternSkewX, -patternSkewY);
patternMatrix.scale(pat->scaleX, pat->scaleY);
patternMatrix.scale(patternScaleX / 100.0 , patternScaleY / 100.0);
bool mirrorX, mirrorY;
item->strokePatternFlip(mirrorX, mirrorY);
if (mirrorX)
patternMatrix.scale(-1, 1);
if (mirrorY)
patternMatrix.scale(1, -1);
PutStream("Pattern" + QString::number(patHash) + " [" + ToStr(patternMatrix.m11()) + " " + ToStr(patternMatrix.m12()) + " " + ToStr(patternMatrix.m21()) + " " + ToStr(patternMatrix.m22()) + " " + ToStr(patternMatrix.dx()) + " " + ToStr(patternMatrix.dy()) + "] makepattern setpattern\n");
PutStream("stroke\n");
}
void PSLib::HandleMeshGradient(PageItem* item)
{
QString hs,ss,vs,ks;
double ch,cs,cv,ck;
QStringList cols;
QStringList colorValues;
QStringList spotColorSet;
QStringList tmpAddedColors;
tmpAddedColors.clear();
QList<int> colsSh;
for (int grow = 0; grow < item->meshGradientArray.count(); grow++)
{
for (int gcol = 0; gcol < item->meshGradientArray[grow].count(); gcol++)
{
MeshPoint mp1 = item->meshGradientArray[grow][gcol];
cols.append(mp1.colorName);
if (!m_Doc->PageColors.contains(mp1.colorName))
{
if (!tmpAddedColors.contains(mp1.colorName))
{
tmpAddedColors.append(mp1.colorName);
ScColor tmp;
tmp.setSpotColor(false);
tmp.setRegistrationColor(false);
tmp.fromQColor(mp1.color);
m_Doc->PageColors.insert(mp1.colorName, tmp);
}
}
colsSh.append(mp1.shade);
if (spotMap.contains(mp1.colorName))
{
if (!spotColorSet.contains(mp1.colorName))
spotColorSet.append(mp1.colorName);
}
}
}
for (int ac = 0; ac < cols.count(); ac++)
{
QString colorVal = "";
if ((Options.useSpotColors) && ((spotColorSet.count() > 0) && (spotColorSet.count() < 28)) && (!GraySc))
{
if (spotColorSet.contains(cols.at(ac)))
{
colorVal = "0 0 0 0";
for (int sc = 0; sc < spotColorSet.count(); sc++)
{
if (spotColorSet.at(sc) == cols.at(ac))
colorVal += " " + ToStr(colsSh[ac] / 100.0);
else
colorVal += " 0";
}
}
else
{
SetColor(cols.at(ac), colsSh.at(ac), &ch, &cs, &cv, &ck);
colorVal += hs.setNum(ch) + " " + ss.setNum(cs) + " " + vs.setNum(cv) + " " + ks.setNum(ck);
for (int sc = 0; sc < spotColorSet.count(); sc++)
{
colorVal += " 0";
}
}
colorValues.append(colorVal);
}
else
{
SetColor(cols.at(ac), colsSh.at(ac), &ch, &cs, &cv, &ck);
if (GraySc)
colorVal += hs.setNum(1.0 - qMin(0.3 * ch + 0.59 * cs + 0.11 * cv + ck, 1.0));
else
colorVal += hs.setNum(ch) + " " + ss.setNum(cs) + " " + vs.setNum(cv) + " " + ks.setNum(ck);
if (DoSep)
{
int pla = Plate - 1 < 0 ? 3 : Plate - 1;
QStringList cols2 = colorVal.split(" ", Qt::SkipEmptyParts);
colorVal = ToStr(1 - ScCLocale::toDoubleC(cols2[pla]));
}
colorValues.append(colorVal);
}
}
for (int grow = 0; grow < item->meshGradientArray.count() - 1; grow++)
{
PutStream("gs\n");
PutStream("<<\n");
PutStream("/PatternType 2\n");
PutStream("/Shading\n");
PutStream("<<\n");
PutStream("/ShadingType 7\n");
if ((DoSep) || (GraySc))
{
PutStream("/ColorSpace /DeviceGray\n");
}
else if ((Options.useSpotColors) && ((spotColorSet.count() > 0) && (spotColorSet.count() < 28)))
{
PutStream("/ColorSpace [ /DeviceN [/Cyan /Magenta /Yellow /Black");
for (int sc = 0; sc < spotColorSet.count(); sc++)
{
PutStream(" (" + spotColorSet.at(sc) + ")");
}
PutStream("]\n");
PutStream("/DeviceCMYK\n");
PutStream("{\n");
int maxSp = spotColorSet.count() - 1;
for (int sc = 0; sc < spotColorSet.count(); sc++)
{
double cc(0), mc(0), yc(0), kc(0);
CMYKColorF cmykValues;
ScColorEngine::getCMYKValues(m_Doc->PageColors[spotColorSet.at(maxSp - sc)], m_Doc, cmykValues);
cmykValues.getValues(cc, mc, yc, kc);
if (sc == 0)
PutStream("dup " + ToStr(cc) + " mul ");
else
PutStream(IToStr(sc * 4 + 1) + " -1 roll dup " + ToStr(cc) + " mul ");
PutStream("exch dup " + ToStr(mc) + " mul ");
PutStream("exch dup " + ToStr(yc) + " mul ");
PutStream("exch " + ToStr(kc) + " mul\n");
}
for (int sc = 0; sc < spotColorSet.count(); sc++)
{
PutStream("8 -1 roll 5 -1 roll add 7 -1 roll 5 -1 roll add 6 -1 roll 5 -1 roll add 5 -1 roll 5 -1 roll add\n");
}
PutStream("} ]\n");
}
else
{
PutStream("/ColorSpace /DeviceCMYK\n");
}
PutStream("/DataSource [\n");
QString vertStream;
QTextStream vst(&vertStream, QIODevice::WriteOnly);
quint8 flg = 0;
for (int gcol = 0; gcol < item->meshGradientArray[grow].count() - 1; gcol++)
{
MeshPoint mp1 = item->meshGradientArray[grow][gcol];
MeshPoint mp2 = item->meshGradientArray[grow][gcol+1];
MeshPoint mp3 = item->meshGradientArray[grow+1][gcol+1];
MeshPoint mp4 = item->meshGradientArray[grow+1][gcol];
int colInd1 = grow * item->meshGradientArray[grow].count() + gcol;
int colInd2 = grow * item->meshGradientArray[grow].count() + gcol + 1;
int colInd3 = (grow + 1) * item->meshGradientArray[grow].count() + gcol + 1;
int colInd4 = (grow + 1) * item->meshGradientArray[grow].count() + gcol;
vst << flg << "\n";
vst << mp4.gridPoint.x() << " " << -mp4.gridPoint.y() << " " << mp4.controlTop.x() << " " << -mp4.controlTop.y() << " " << mp1.controlBottom.x() << " " << -mp1.controlBottom.y() << "\n";
vst << mp1.gridPoint.x() << " " << -mp1.gridPoint.y() << " " << mp1.controlRight.x() << " " << -mp1.controlRight.y() << " " << mp2.controlLeft.x() << " " << -mp2.controlLeft.y() << "\n";
vst << mp2.gridPoint.x() << " " << -mp2.gridPoint.y() << " " << mp2.controlBottom.x() << " " << -mp2.controlBottom.y() << " " << mp3.controlTop.x() << " " << -mp3.controlTop.y() << "\n";
vst << mp3.gridPoint.x() << " " << -mp3.gridPoint.y() << " " << mp3.controlLeft.x() << " " << -mp3.controlLeft.y() << " " << mp4.controlRight.x() << " " << -mp4.controlRight.y() << "\n";
vst << mp4.controlColor.x() << " " << -mp4.controlColor.y() << "\n";
vst << mp1.controlColor.x() << " " << -mp1.controlColor.y() << "\n";
vst << mp2.controlColor.x() << " " << -mp2.controlColor.y() << "\n";
vst << mp3.controlColor.x() << " " << -mp3.controlColor.y() << "\n";
vst << colorValues[colInd4] << " " << colorValues[colInd1] << " " << colorValues[colInd2] << " " << colorValues[colInd3] << "\n";
}
PutStream(vertStream);
PutStream("]\n");
PutStream(">>\n");
PutStream(">>\n");
PutStream("[1 0 0 1 0 0] makepattern\n");
PutStream("setpattern\n");
if (fillRule)
PutStream("eofill\n");
else
PutStream("fill\n");
PutStream("gr\n");
}
PS_newpath();
if (tmpAddedColors.count() != 0)
{
for (int cd = 0; cd < tmpAddedColors.count(); cd++)