Subversion Repositories Scribus

Rev

Rev 18454 | Rev 18734 | 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 "cmsettings.h"
#include "commonstrings.h"
#include "scconfig.h"
#include "pluginapi.h"
#include "pageitem_latexframe.h"
#include "pageitem_pathtext.h"
#include "pageitem_table.h"
#include "prefsmanager.h"
#include "scclocale.h"
#include "sccolorengine.h"
#include "scfonts.h"
#include "scribusapp.h"
#include "scribusdoc.h"
#include "scribus.h"
#include "scribuscore.h"
#include "selection.h"
#include "scpattern.h"
#include "scstreamfilter_ascii85.h"
#include "scstreamfilter_flate.h"
#include "tableutils.h"
#include "ui/multiprogressdialog.h"
#include "util.h"
#include "util_formats.h"
#include "util_math.h"

using namespace TableUtils;

PSLib::PSLib(PrintOptions &options, bool psart, SCFonts &AllFonts, QMap<QString, QMap<uint, FPointArray> > DocFonts, ColorList DocColors, bool pdf, bool spot)
{
        Options = options;
        optimization = OptimizeCompat;
        usingGUI=ScCore->usingGUI();
        abortExport=false;
        QString tmp, tmp2, tmp3, tmp4, CHset;
        QStringList wt;
        Seiten = 0;
        User = "";
        Creator = "Scribus" + QString(VERSION);
        Titel = "";
        FillColor = "0.0 0.0 0.0 0.0";
        StrokeColor = "0.0 0.0 0.0 0.0";
        Header = psart ? "%!PS-Adobe-3.0\n" : "%!PS-Adobe-3.0 EPSF-3.0\n";
        BBox = "";
        BBoxH = "";
        psExport = psart;
        isPDF = pdf;
        UsedFonts.clear();
        Fonts = "";
        FontDesc = "";
        GraySc = false;
        DoSep = false;
        abortExport = false;
        useSpotColors = spot;
        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";
        Farben = "";
        FNamen = "";
        CMYKColor cmykValues;
        ColorList::Iterator itf;
        int c, m, y, k;
        int spotCount = 1;
        bool erst = true;
        colorsToUse = DocColors;
        spotMap.clear();
        colorDesc = "";
        for (itf = DocColors.begin(); itf != DocColors.end(); ++itf)
        {
                if (((itf->isSpotColor()) || (itf->isRegistrationColor())) && (useSpotColors))
                {
                        ScColorEngine::getCMYKValues(*itf, DocColors.document(), cmykValues);
                        cmykValues.getValues(c, m, y, k);
                        colorDesc += "/Spot"+QString::number(spotCount)+" { [ /Separation (";
                        if (DocColors[itf.key()].isRegistrationColor())
                                colorDesc += "All";
                        else
                                colorDesc += itf.key();
                        colorDesc += ")\n";
                        colorDesc += "/DeviceCMYK\n{\ndup "+ToStr(static_cast<double>(c) / 255)+"\nmul exch dup ";
                        colorDesc += ToStr(static_cast<double>(m) / 255)+"\nmul exch dup ";
                        colorDesc += ToStr(static_cast<double>(y) / 255)+"\nmul exch ";
                        colorDesc += ToStr(static_cast<double>(k) / 255)+" 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") && DocColors[itf.key()].isSpotColor())
                {
                        ScColorEngine::getCMYKValues(DocColors[itf.key()], DocColors.document(), cmykValues);
                        cmykValues.getValues(c, m, y, k);
                        if (!erst)
                        {
                                Farben += "%%+ ";
                                FNamen += "%%+ ";
                        }
                        Farben += ToStr(static_cast<double>(c) / 255) + " " + ToStr(static_cast<double>(m) / 255) + " ";
                        Farben += ToStr(static_cast<double>(y) / 255) + " " + ToStr(static_cast<double>(k) / 255) + " (" + itf.key() + ")\n";
                        FNamen += "(" + itf.key() + ")\n";
                        erst = false;
                }
        }
        QMap<QString, QString> psNameMap;
        QMap<QString, QMap<uint, FPointArray> >::Iterator it;
        int a = 0;
        for (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
                ScFace &face (AllFonts[it.key()]);
                ScFace::FontType type = face.type();
                QString encodedName = face.psName().simplified().replace( QRegExp("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]"), "_" );

                if ((type == ScFace::TTF) || (face.isOTF()) || (face.subset()) || psNameMap.contains(encodedName))
                {
                        QMap<uint, FPointArray>& RealGlyphs(it.value());
                        // 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(RealGlyphs.count()+1) + " dict def\n";
                        FontDesc += encodedName + " begin\n";
                        QMap<uint,FPointArray>::Iterator ig;
                        for (ig = RealGlyphs.begin(); ig != RealGlyphs.end(); ++ig)
                        {
                                FontDesc += "/G"+IToStr(ig.key())+" { newpath\n";
                                FPoint np, np1, np2;
                                bool nPath = true;
                                if (ig.value().size() > 3)
                                {
                                        for (int poi = 0; poi < ig.value().size()-3; poi += 4)
                                        {
                                                if (ig.value().point(poi).x() > 900000)
                                                {
                                                        FontDesc += "cl\n";
                                                        nPath = true;
                                                        continue;
                                                }
                                                if (nPath)
                                                {
                                                        np = ig.value().point(poi);
                                                        FontDesc += ToStr(np.x()) + " " + ToStr(-np.y()) + " m\n";
                                                        nPath = false;
                                                }
                                                np = ig.value().point(poi+1);
                                                np1 = ig.value().point(poi+3);
                                                np2 = ig.value().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);
                }
                else
                {
                        UsedFonts.insert(it.key(), "/Fo"+IToStr(a));
                        Fonts += "/Fo" + IToStr(a) + " /" + encodedName + " findfont definefont pop\n";
                        if (AllFonts[it.key()].embedPs())
                        {
                                QString tmp;
                                if(face.EmbedFont(tmp))
                                {
                                        FontDesc += "%%BeginFont: " + encodedName + "\n";
                                        FontDesc += tmp + "\n%%EndFont\n";
                                }
                        }
                        GlyphList gl;
                        face.glyphNames(gl);
                        GlyphsOfFont.insert(it.key(), gl);
                        a++;
                }
                psNameMap.insert(encodedName, face.scName());
        }
        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";
}

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(QString art, QString was)
{
        if (art == "Author")
                User = was;
        if (art == "Creator")
                Creator = was;
        if (art == "Title")
                Titel = was;
}

bool PSLib::PS_set_file(QString fn)
{
        Spool.setFileName(fn);
        if (Spool.exists())
                Spool.remove();
        bool ret = Spool.open(QIODevice::WriteOnly);
        spoolStream.setDevice(&Spool);
        return ret;
}

bool PSLib::PS_begin_doc(ScribusDoc *doc, double x, double y, double width, double height, int numpage, bool doDev, bool sep, bool farb, bool ic, bool gcr)
{
        m_Doc = doc;
        PutStream(Header);
        PutStream("%%For: " + User + "\n");
        PutStream("%%Title: " + Titel + "\n");
        PutStream("%%Creator: " + Creator + "\n");
        PutStream("%%Pages: " + IToStr(numpage) + "\n");
        if(width < height || !psExport)
        {
                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";
        }
 //     if (!Art)
//      {
                PutStream(BBox);
                PutStream(BBoxH);
//      }
        if (!FNamen.isEmpty())
                PutStream("%%DocumentCustomColors: "+FNamen);
        if (!Farben.isEmpty())
                PutStream("%%CMYKCustomColor: "+Farben);
        PutStream("%%LanguageLevel: 3\n");
        PutStream("%%EndComments\n");
        PutStream(Prolog);
        PutStream("%%BeginSetup\n");
        if (isPDF)
                PutStream("/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse\n");
        if (!FontDesc.isEmpty())
                PutStream(FontDesc);
        if ((!colorDesc.isEmpty()) && (!sep))
                PutStream(colorDesc);
//      PutStream("Scribusdict begin\n");
        PutStream(Fonts);
        if (GraySc)
                PutStream(GrayCalc);
        Optimization optim = optimization;
        optimization = OptimizeSize;
        QStringList patterns = m_Doc->getPatternDependencyList(m_Doc->getUsedPatterns());
        for (int c = 0; c < patterns.count(); ++c)
        {
                ScPattern pa = m_Doc->docPatterns[patterns[c]];
                for (int em = 0; em < pa.items.count(); ++em)
                {
                        PageItem* item = pa.items.at(em);
                        if ((item->asImageFrame()) && (item->PictureIsAvailable) && (!item->Pfile.isEmpty()) && (item->printEnabled()) && (!sep) && (farb))
                        {
                                if (!PS_ImageData(item, item->Pfile, item->itemName(), item->IProfile, item->UseEmbedded, ic))
                                        return false;
                        }
                }
                uint patHash = qHash(patterns[c]);
                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 em = 0; em < pa.items.count(); ++em)
                {
                        PageItem* item = pa.items.at(em);
                        PutStream("{\n");
                        PS_save();
                        PS_translate(item->gXpos, pa.height - item->gYpos);
                        ProcessItem(m_Doc, m_Doc->Pages->at(0), item, 0, sep, farb, ic, gcr, false, true, true);
                        PS_restore();
                        PutStream("} exec\n");
                }
                spoolStream.setDevice(spStream);
                PutStream(buf);
                PutStream("} def\n");
                PutStream("end\n");
        }
        optimization = optim;
//      PutStream("end\n");
//      PutStream("%%EndSetup\n");
        Prolog = "";
        FontDesc = "";
        return true;
}

QString PSLib::PSEncode(QString in)
{
        static QRegExp badchars("[\\s\\/\\{\\[\\]\\}\\<\\>\\(\\)\\%]");
        QString tmp = "";
        tmp = in.simplified().replace( badchars, "_" );
        return tmp;
}

void PSLib::PS_TemplateStart(QString Name)
{
        PutStream("/"+PSEncode(Name)+"\n{\n");
}

void PSLib::PS_UseTemplate(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;
        Seiten++;
        PutStream("%%Page: " + IToStr(Seiten) + " " + IToStr(Seiten) + "\n");
        PutStream("%%PageOrientation: ");
// when creating EPS files determine the orientation from the bounding box
        if (!psExport)
        {
                if ((pg->width() - Ma->Left - Ma->Right) <= (pg->height() - Ma->Bottom - Ma->Top))
                        PutStream("Portrait\n");
                else
                        PutStream("Landscape\n");
        }
        else
        {
                if (pg->orientation() == 0)
                {
                        PutStream("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("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 ((psExport) && (Options.setDevParam))
        {
                PutStream("<< /PageSize [ "+ToStr(maxBoxX)+" "+ToStr(maxBoxY)+" ]\n");
                PutStream(">> setpagedevice\n");
        }
        PutStream("save\n");
        if (pg->orientation() == 1 && psExport)
                PutStream("90 rotate 0 "+IToStr(qRound(maxBoxY))+" neg translate\n");
        PutStream("/DeviceCMYK setcolorspace\n");
        PutStream(ToStr(bleedLeft+markOffs)+" "+ToStr(Options.bleeds.Bottom+markOffs)+" tr\n");
        ActPage = pg;
        if (Clipping)
        {
                PDev = ToStr(Ma->Left) + " " + ToStr(Ma->Bottom) + " m\n";
                PDev += ToStr(pg->width() - Ma->Right) + " " + ToStr(Ma->Bottom) + " li\n";
                PDev += ToStr(pg->width() - Ma->Right) + " " + ToStr(pg->height() - Ma->Top) + " li\n";
                PDev += ToStr(Ma->Left) + " " + ToStr(pg->height() - Ma->Top) + " li cl clip newpath\n";
                PutStream(PDev);
        }
}

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(ActPage, bleedLeft, bleedRight);
        double maxBoxX = ActPage->width()+bleedLeft+bleedRight+markOffs*2.0;
        double maxBoxY = ActPage->height()+Options.bleeds.Bottom+Options.bleeds.Top+markOffs*2.0;
        PutStream("gs\n");
        if(ActPage->orientation() == 1 && psExport)
                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_selectfont(QString f, double s)
{
        PutStream(UsedFonts[f] + " " + ToStr(s) + " se\n");
}

void PSLib::PS_fill()
{
        if (fillRule)
                PutStream(FillColor + " cmyk eofill\n");
        else
                PutStream(FillColor + " cmyk fill\n");
}

void PSLib::PS_fillspot(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(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_xyG(QString font, uint glyph, double x, double y, QString colorName, double shade)
{
        QString glyphName;
        glyphName = GlyphsOfFont[font].contains(glyph) ? GlyphsOfFont[font][glyph].second : QString(".notdef");

        QString colorString;
        ScColor& color(colorsToUse[colorName]);
        bool spot = false;
        if (((color.isSpotColor()) || (color.isRegistrationColor())) && (useSpotColors))
        {
                if (!DoSep)
                {
                        colorString = ToStr(shade / 100.0)+" "+spotMap[colorName];
                        spot = true;
                }
                else if ((colorName == currentSpot) || (color.isRegistrationColor()))
                        colorString = "0 0 0 "+ToStr(shade / 100.0);
                else
                        colorString = "0 0 0 0";
        }
        else
        {
                int c, m, y, k;
                SetColor(color, shade, &c, &m, &y, &k, Options.doGCR);
                if (!DoSep || (Plate == 0 || Plate == 1 || Plate == 2 || Plate == 3))
                        colorString = ToStr(c / 255.0) + " " + ToStr(m / 255.0) + " " + ToStr(y / 255.0) + " " + ToStr(k / 255.0);
                else
                        colorString = "0 0 0 0";
        }
        if (spot)
        {
                PutStream(colorString + "\n");
                PutStream("/"+glyphName+" "+ToStr(x)+" "+ToStr(y)+" shgsp\n");
        }
        else
                PutStream("/"+glyphName+" "+ToStr(x)+" "+ToStr(y)+" "+colorString+" shg\n");
}

void PSLib::PS_show(double x, double y)
{
        PS_moveto(x, y);
        PutStream("/hyphen glyphshow\n");
}

void PSLib::PS_showSub(uint chr, 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 *c, QString fn, QString Name, QString Prof, bool UseEmbedded, bool UseProf)
{
        bool dummy;
        QByteArray tmp;
        QFileInfo fi = QFileInfo(fn);
        QString ext = fi.suffix().toLower();
        if (ext.isEmpty())
                ext = getImageType(fn);
        if (extensionIndicatesEPS(ext) && (c->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 = c->pixm.imgInfo.RequestProps;
        image.imgInfo.isRequest = c->pixm.imgInfo.isRequest;
        CMSettings cms(c->doc(), Prof, c->IRender);
        cms.allowColorManagement(UseProf);
        cms.setUseEmbeddedProfile(UseEmbedded);
        if (!image.loadPicture(fn, c->pixm.imgInfo.actualPageNumber, cms, ScImage::CMYKData, 300, &dummy))
        {
                PS_Error_ImageLoadFailure(fn);
                return false;
        }
        image.applyEffect(c->effectsInUse, colorsToUse, true);
        QByteArray maskArray;
        if (c->pixm.imgInfo.type != ImageType7)
        {
                bool alphaLoaded = image.getAlpha(fn, c->pixm.imgInfo.actualPageNumber, maskArray, false, true, 300);
                if (!alphaLoaded)
                {
                        PS_Error_MaskLoadFailure(fn);
                        return false;
                }
        }
        if ((maskArray.size() > 0) && (c->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 *c, double x, double y, QString fn, double scalex, double scaley, QString Prof, bool UseEmbedded, bool UseProf, QString Name)
{
        bool dummy;
        QByteArray tmp;
        QFileInfo fi = QFileInfo(fn);
        QString ext = fi.suffix().toLower();
        if (ext.isEmpty())
                ext = getImageType(fn);
        if (extensionIndicatesEPS(ext) && (c->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(-c->BBoxX+x * scalex) + " " + ToStr(y * scalex) + " tr\n");
                        int h = c->pixm.height();
                        PutStream("0 " + ToStr(h*scaley) + " tr\n");
                        PutStream(ToStr(-c->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;
        }
        else
        {
                ScImage image;
                QByteArray imgArray;
                image.imgInfo.valid = false;
                image.imgInfo.clipPath = "";
                image.imgInfo.PDSpathData.clear();
                image.imgInfo.layerInfo.clear();
                image.imgInfo.RequestProps = c->pixm.imgInfo.RequestProps;
                image.imgInfo.isRequest = c->pixm.imgInfo.isRequest;
                CMSettings cms(c->doc(), Prof, c->IRender);
                cms.allowColorManagement(UseProf);
                cms.setUseEmbeddedProfile(UseEmbedded);
                int resolution = 300;
                if (c->asLatexFrame())
                        resolution = c->asLatexFrame()->realDpi();
                else if (c->pixm.imgInfo.type == ImageType7)
                        resolution = 72;
//              int resolution = (c->pixm.imgInfo.type == ImageType7) ? 72 : 300;
                if ( !image.loadPicture(fn, c->pixm.imgInfo.actualPageNumber, cms, ScImage::CMYKData, resolution, &dummy) )
                {
                        PS_Error_ImageLoadFailure(fn);
                        return false;
                }
                image.applyEffect(c->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(-c->imageRotation()) + " ro\n");
                PutStream("0 " + ToStr(-h*scaley) + " tr\n");
                if ((extensionIndicatesPDF(ext)) && (!c->asLatexFrame()))
                {
                        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 = c->pixm.imgInfo.RequestProps;
                img2.imgInfo.isRequest = c->pixm.imgInfo.isRequest;
                if (c->pixm.imgInfo.type != ImageType7)
                {
                        bool alphaLoaded = img2.getAlpha(fn, c->pixm.imgInfo.actualPageNumber, maskArray, false, true, resolution);
                        if (!alphaLoaded)
                        {
                                PS_Error_MaskLoadFailure(fn);
                                return false;
                        }
                }
                if ((maskArray.size() > 0) && (c->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, 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(QString text, uint Seite)
{
        PutStream("[/Title ("+text+") /Page "+IToStr(Seite)+" /View [/Fit]\n");
        PutStream("/OUT pdfmark\n");
}

void PSLib::PDF_Annotation(PageItem *item, 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(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(void)
{
        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(void)
{
        PS_Error( tr("Insufficient memory for processing an image"));
}

int PSLib::CreatePS(ScribusDoc* Doc, PrintOptions &options)
{
        bool errorOccured = false;
        Options = options;
        std::vector<int> &pageNs = options.pageNumbers;
        bool sep = options.outputSeparations;
        QString SepNam = options.separationName;
        QStringList spots = options.allSeparations;
        bool farb = options.useColor;
        bool Hm = options.mirrorH;
        bool Vm = options.mirrorV;
        bool Ic = options.useICC;
        bool gcr = options.doGCR;
        bool doDev = options.setDevParam;
        bool doClip = options.doClip;
        int sepac;
        int pagemult;
        if ((sep) && (SepNam == QObject::tr("All")))
                pagemult = spots.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", Doc->documentInfo().author());
        PS_set_Info("Title", Doc->documentInfo().title());
        if (!farb)
                PS_setGray();
        applyICC = Ic;
        if ((Doc->HasCMS) && (ScCore->haveCMS()) && (applyICC))
                solidTransform = Doc->colorEngine.createTransform(Doc->DocInputCMYKProf, Format_CMYK_16, Doc->DocPrinterProf, Format_CMYK_16, Doc->IntentColors, 0);
        else
                applyICC = false;
        if (usingGUI)
        {
                QString title=QObject::tr("Exporting PostScript File");
                if (psExport)
                        title=QObject::tr("Printing File");
                progressDialog=new MultiProgressDialog(title, CommonStrings::tr_Cancel, Doc->scMW());
                if (progressDialog==0)
                        usingGUI=false;
                else
                {
                        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()+Doc->MasterPages.count());
                        progressDialog->setTotalSteps("EMP", 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=Doc->m_Selection->count();
        if ((!psExport) && (docSelectionCount != 0))
        {
                double minx = 999999.9;
                double miny = 999999.9;
                double maxx = -999999.9;
                double maxy = -999999.9;
                for (uint ep = 0; ep < docSelectionCount; ++ep)
                {
                        PageItem* currItem = 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 -= Doc->Pages->at(pgNum)->xOffset();
                gy -= Doc->Pages->at(pgNum)->yOffset();
                errorOccured = !PS_begin_doc(Doc, gx, Doc->pageHeight() - (gy+gh), gx + gw, Doc->pageHeight() - gy, 1*pagemult, false, sep, farb, Ic, gcr);
        }
        else
        {
                uint a;
                double maxWidth = 0.0;
                double maxHeight = 0.0;
                for (uint aa = 0; aa < pageNs.size(); ++aa)
                {
                        a = pageNs[aa]-1;
                        maxWidth = qMax(Doc->Pages->at(a)->width(), maxWidth);
                        maxHeight = qMax(Doc->Pages->at(a)->height(), maxHeight);
                }
                errorOccured = !PS_begin_doc(Doc, 0.0, 0.0, maxWidth, maxHeight, pageNs.size()*pagemult, doDev, sep, farb, Ic, gcr);
        }
        int ap=0;
        for (; ap < Doc->MasterPages.count() && !abortExport && !errorOccured; ++ap)
        {
                progressDialog->setOverallProgress(ap);
                progressDialog->setProgress("EMP", ap);
                ScQApp->processEvents();
                if (Doc->MasterItems.count() != 0)
                {
                        int Lnr = 0;
                        ScLayer ll;
                        ll.isPrintable = false;
                        ll.ID = 0;
                        for (int lam = 0; lam < Doc->Layers.count() && !abortExport && !errorOccured; ++lam)
                        {
                                Doc->Layers.levelToLayer(ll, Lnr);
                                if (ll.isPrintable)
                                {
                                        for (int api = 0; api < Doc->MasterItems.count() && !abortExport; ++api)
                                        {
                                                QString tmps;
                                                PageItem *it = Doc->MasterItems.at(api);
                                                if (usingGUI)
                                                        ScQApp->processEvents();
                                                if ((it->LayerID != ll.ID) || (!it->printEnabled()))
                                                        continue;
                                                double bLeft, bRight, bBottom, bTop;
                                                GetBleeds(Doc->MasterPages.at(ap), bLeft, bRight, bBottom, bTop);
                                                double x  = Doc->MasterPages.at(ap)->xOffset() - bLeft;
                                                double y  = Doc->MasterPages.at(ap)->yOffset() - bTop;
                                                double w  = Doc->MasterPages.at(ap)->width() + bLeft + bRight;
                                                double h1 = Doc->MasterPages.at(ap)->height()+ bBottom + bTop;
                                                double ilw = it->lineWidth();
                                                double x2 = it->BoundingX - ilw / 2.0;
                                                double y2 = it->BoundingY - ilw / 2.0;
                                                double w2 = qMax(it->BoundingW + ilw, 1.0);
                                                double h2 = qMax(it->BoundingH + ilw, 1.0);
                                                if (!( qMax( x, x2 ) <= qMin( x+w, x2+w2 ) && qMax( y, y2 ) <= qMin( y+h1, y2+h2 )))
                                                        continue;
                                                if ((it->OwnPage != static_cast<int>(Doc->MasterPages.at(ap)->pageNr())) && (it->OwnPage != -1))
                                                        continue;
                                                if ((optimization == OptimizeSize) && it->asImageFrame() && it->PictureIsAvailable && (!it->Pfile.isEmpty()) && it->printEnabled() && (!sep) && farb)
                                                {
                                                        errorOccured = !PS_ImageData(it, it->Pfile, it->itemName(), it->IProfile, it->UseEmbedded, Ic);
                                                        if (errorOccured) break;
                                                }
                                                PS_TemplateStart(QString("mp_obj_%1_%2").arg(ap).arg(qHash(it)));
                                                ProcessItem(Doc, Doc->MasterPages.at(ap), it, ap+1, sep, farb, Ic, gcr, true);
                                                PS_TemplateEnd();
                                        }
                                }
                                Lnr++;
                                if (errorOccured) break;
                        }
                }
                if (errorOccured) break;
        }
        sepac = 0;
        uint aa = 0;
        uint a;
        PutStream("%%EndSetup\n");
        while (aa < pageNs.size() && !abortExport && !errorOccured)
        {
                progressDialog->setProgress("EP", aa);
                progressDialog->setOverallProgress(ap+aa);
                if (usingGUI)
                        ScQApp->processEvents();
                a = pageNs[aa]-1;
                ScPage* page = Doc->Pages->at(a);
                if ((!psExport) && (Doc->m_Selection->count() != 0))
                {
                        MarginStruct Ma;
                        Ma.Left = gx;
                        Ma.Top = gy;
                        Ma.Bottom = page->height() - (gy + gh);
                        Ma.Right  = 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 (sep)
                {
                        if (SepNam == QObject::tr("Black"))
                                PS_plate(0);
                        else if (SepNam == QObject::tr("Cyan"))
                                PS_plate(1);
                        else if (SepNam == QObject::tr("Magenta"))
                                PS_plate(2);
                        else if (SepNam == QObject::tr("Yellow"))
                                PS_plate(3);
                        else if (SepNam == QObject::tr("All"))
                                PS_plate(sepac, spots[sepac]);
                        else
                                PS_plate(4, SepNam);
                }
                ScLayer ll;
                ll.isPrintable = false;
                for (int lam = 0; lam < Doc->Layers.count() && !abortExport && !errorOccured; ++lam)
                {
                        Doc->Layers.levelToLayer(ll, lam);
                        if (!ll.isPrintable)
                                continue;
                        if (!page->MPageNam.isEmpty() && !abortExport && !errorOccured)
                        {
                                errorOccured |= !ProcessMasterPageLayer(Doc, page, ll, a, sep, farb, Ic, gcr);
                        }
                        if (!abortExport && !errorOccured)
                        {
                                errorOccured |= !ProcessPageLayer(Doc, page, ll, a+1, sep, farb, Ic, gcr);
                        }
                }
                if (!abortExport && !errorOccured)
                        PS_end_page();
                if (sep)
                {
                        if (SepNam != QObject::tr("All"))
                                aa++;
                        else
                        {
                                if (sepac == static_cast<int>(spots.count()-1))
                                {
                                        aa++;
                                        sepac = 0;
                                }
                                else
                                        sepac++;
                        }
                }
                else
                        aa++;
        }
        PS_close();
        if (usingGUI) progressDialog->close();
        if (errorOccured)
                return 1;
        else if (abortExport)
                return 2; //CB Lets leave 1 for general error condition
        return 0;
}

bool PSLib::ProcessItem(ScribusDoc* Doc, ScPage* a, PageItem* c, uint PNr, bool sep, bool farb, bool ic, bool gcr, bool master, bool embedded, bool useTemplate)
{
        double tsz;
        int h, s, v, k;
        int d;
        int savedOwnPage;
        ScText *hl;
        QVector<double> dum;
        QChar chstr;
        QString tmps;
        if (c->printEnabled())
        {
                fillRule = true;
                PS_save();
                if (c->doOverprint)
                {
                        PutStream("true setoverprint\n");
                        PutStream("true setoverprintmode\n");
                }
                if (c->fillColor() != CommonStrings::None)
                {
                        SetColor(c->fillColor(), c->fillShade(), &h, &s, &v, &k, gcr);
                        PS_setcmykcolor_fill(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                }
                if (c->lineColor() != CommonStrings::None)
                {
                        SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                }
                PS_setlinewidth(c->lineWidth());
                PS_setcapjoin(c->PLineEnd, c->PLineJoin);
                PS_setdash(c->PLineArt, c->DashOffset, c->DashValues);
                if (!embedded)
                {
                        PS_translate(c->xPos() - a->xOffset(), a->height() - (c->yPos() - a->yOffset()));
                }
                if (c->rotation() != 0)
                        PS_rotate(-c->rotation());
                switch (c->itemType())
                {
                case PageItem::ImageFrame:
                case PageItem::LatexFrame:
                        if (master)
                                break;
                        if ((c->fillColor() != CommonStrings::None) || (c->GrType != 0))
                        {
                                SetClipPath(&c->PoLine);
                                PS_closepath();
                                if ((c->GrType != 0) && (master == false))
                                        HandleGradientFillStroke(c, gcr, false);
                                else
                                        putColor(c->fillColor(), c->fillShade(), true);
                                PS_newpath();
                        }
                        PS_save();
                        if (c->imageFlippedH())
                        {
                                PS_translate(c->width(), 0);
                                PS_scale(-1, 1);
                        }
                        if (c->imageFlippedV())
                        {
                                PS_translate(0, -c->height());
                                PS_scale(1, -1);
                        }
                        if (c->imageClip.size() != 0)
                        {
                                SetClipPath(&c->imageClip);
                                PS_closepath();
                                PS_clip(true);
                        }
                        SetClipPath(&c->PoLine);
                        PS_closepath();
                        PS_clip(true);
                        if ((c->PictureIsAvailable) && (!c->Pfile.isEmpty()))
                        {
                                bool imageOk = false;
                                PS_translate(0, -c->BBoxH*c->imageYScale());
                                if ((optimization == OptimizeSize) && (((!a->pageName().isEmpty()) && !sep && farb) || useTemplate))
                                        imageOk = PS_image(c, c->imageXOffset(), -c->imageYOffset(), c->Pfile, c->imageXScale(), c->imageYScale(), c->IProfile, c->UseEmbedded, ic, c->itemName());
                                else
                                        imageOk = PS_image(c, c->imageXOffset(), -c->imageYOffset(), c->Pfile, c->imageXScale(), c->imageYScale(), c->IProfile, c->UseEmbedded, ic);
                                if (!imageOk) return false;
                        }
                        PS_restore();
                        if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()) || (c->GrTypeStroke > 0)))
                        {
                                if (c->NamedLStyle.isEmpty()) // && (c->lineWidth() != 0.0))
                                {
                                        if ((!c->strokePattern().isEmpty()) && (c->patternStrokePath))
                                        {
                                                QPainterPath path = c->PoLine.toQPainterPath(false);
                                                HandleBrushPattern(c, path, a, PNr, sep, farb, ic, gcr, master);
                                        }
                                        else
                                        {
                                                PS_setlinewidth(c->lineWidth());
                                                PS_setcapjoin(c->PLineEnd, c->PLineJoin);
                                                PS_setdash(c->PLineArt, c->DashOffset, c->DashValues);
                                                SetClipPath(&c->PoLine);
                                                PS_closepath();
                                                if (!c->strokePattern().isEmpty())
                                                        HandleStrokePattern(c);
                                                else if (c->GrTypeStroke > 0)
                                                        HandleGradientFillStroke(c, gcr);
                                                else
                                                {
                                                        SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        putColor(c->lineColor(), c->lineShade(), false);
                                                }
                                        }
                                }
                                else
                                {
                                        multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        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(&c->PoLine);
                                                        PS_closepath();
                                                        putColor(ml[it].Color, ml[it].Shade, false);
                                                }
                                        }
                                }
                        }
                        break;
                case PageItem::TextFrame:
                        if (master)
                                break;
                        if ((c->isBookmark || c->isAnnotation()) && (!isPDF))
                                break;
                        if (c->isBookmark)
                        {
                                QString bm = "";
                                QString cc;
                                for (int d = 0; d < c->itemText.length(); ++d)
                                {
                                        if ((c->itemText.text(d) == QChar(13)) || (c->itemText.text(d) == QChar(10)) || (c->itemText.text(d) == QChar(28)))
                                                break;
                                        bm += "\\"+cc.setNum(qMax(c->itemText.text(d).unicode(), (ushort) 32), 8);
                                }
                                PDF_Bookmark(bm, a->pageNr()+1);
                        }
                        if (c->isAnnotation())
                        {
                                if ((c->annotation().Type() == 0) || (c->annotation().Type() == 1) || (c->annotation().Type() == Annotation::Text) || (c->annotation().Type() == Annotation::Link))
                                {
                                        QString bm = "";
                                        QString cc;
                                        for (int d = 0; d < c->itemText.length(); ++d)
                                        {
                                                bm += "\\"+cc.setNum(qMax(c->itemText.text(d).unicode(), (ushort) 32), 8);
                                        }
                                        PDF_Annotation(c, bm, 0, 0, c->width(), -c->height());
                                }
                                break;
                        }
                        if ((c->fillColor() != CommonStrings::None) || (c->GrType != 0))
                        {
                                SetClipPath(&c->PoLine);
                                PS_closepath();
                                if ((c->GrType != 0) && (master == false))
                                        HandleGradientFillStroke(c, gcr, false);
                                else
                                        putColor(c->fillColor(), c->fillShade(), true);
                        }
                        if (c->imageFlippedH())
                        {
                                PS_translate(c->width(), 0);
                                PS_scale(-1, 1);
                        }
                        if (c->imageFlippedV())
                        {
                                PS_translate(0, -c->height());
                                PS_scale(1, -1);
                        }
                        setTextSt(Doc, c, gcr, PNr-1, a, sep, farb, ic, master);
                        if (((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()) || (c->GrTypeStroke > 0)))
                        {
                                PS_setlinewidth(c->lineWidth());
                                PS_setcapjoin(c->PLineEnd, c->PLineJoin);
                                PS_setdash(c->PLineArt, c->DashOffset, c->DashValues);
                                if ((c->NamedLStyle.isEmpty()) && (c->lineWidth() != 0.0))
                                {
                                        if ((!c->strokePattern().isEmpty()) && (c->patternStrokePath))
                                        {
                                                QPainterPath path = c->PoLine.toQPainterPath(false);
                                                HandleBrushPattern(c, path, a, PNr, sep, farb, ic, gcr, master);
                                        }
                                        else
                                        {
                                                SetClipPath(&c->PoLine);
                                                PS_closepath();
                                                if (!c->strokePattern().isEmpty())
                                                        HandleStrokePattern(c);
                                                else if (c->GrTypeStroke > 0)
                                                        HandleGradientFillStroke(c, gcr);
                                                else
                                                {
                                                        SetColor(c->lineColor(), c->lineShade(), &h, &s, &v, &k, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        putColor(c->lineColor(), c->lineShade(), false);
                                                }
                                        }
                                }
                                else
                                {
                                        multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        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(&c->PoLine);
                                                        PS_closepath();
                                                        putColor(ml[it].Color, ml[it].Shade, false);
                                                }
                                        }
                                }
                        }
                        break;
                case PageItem::Line:
                        if (c->NamedLStyle.isEmpty()) // && (c->lineWidth() != 0.0))
                        {
                                if (!c->strokePattern().isEmpty())
                                {
                                        if (c->patternStrokePath)
                                        {
                                                QPainterPath guidePath;
                                                guidePath.moveTo(0, 0);
                                                guidePath.lineTo(c->width(), 0);
                                                HandleBrushPattern(c, guidePath, a, PNr, sep, farb, ic, gcr, master);
                                        }
                                        else
                                        {
                                                PS_moveto(0, 0);
                                                PS_lineto(c->width(), 0);
                                                HandleStrokePattern(c);
                                        }
                                }
                                else if (c->GrTypeStroke > 0)
                                {
                                        PS_moveto(0, 0);
                                        PS_lineto(c->width(), 0);
                                        HandleGradientFillStroke(c, gcr);
                                }
                                else if (c->lineColor() != CommonStrings::None)
                                {
                                        PS_moveto(0, 0);
                                        PS_lineto(c->width(), 0);
                                        putColor(c->lineColor(), c->lineShade(), false);
                                }
                        }
                        else
                        {
                                multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                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(c->width(), 0);
                                                putColor(ml[it].Color, ml[it].Shade, false);
                                        }
                                }
                        }
                        if (c->startArrowIndex() != 0)
                        {
                                QTransform arrowTrans;
                                arrowTrans.scale(-1,1);
                                arrowTrans.scale(c->startArrowScale() / 100.0, c->startArrowScale() / 100.0);
                                drawArrow(c, arrowTrans, c->startArrowIndex(), gcr);
                        }
                        if (c->endArrowIndex() != 0)
                        {
                                QTransform arrowTrans;
                                arrowTrans.translate(c->width(), 0);
                                arrowTrans.scale(c->endArrowScale() / 100.0, c->endArrowScale() / 100.0);
                                drawArrow(c, arrowTrans, c->endArrowIndex(), gcr);
                        }
                        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 ((c->fillColor() != CommonStrings::None) || (c->GrType != 0))
                        {
                                SetClipPath(&c->PoLine);
                                PS_closepath();
                                fillRule = c->fillRule;
                                if (c->GrType != 0)
                                        HandleGradientFillStroke(c, gcr, false);
                                else
                                        putColor(c->fillColor(), c->fillShade(), true);
                        }
                        if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()) || (c->GrTypeStroke > 0))
                        {
                                if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
                                {
                                        if ((!c->strokePattern().isEmpty()) && (c->patternStrokePath))
                                        {
                                                QPainterPath path = c->PoLine.toQPainterPath(false);
                                                HandleBrushPattern(c, path, a, PNr, sep, farb, ic, gcr, master);
                                        }
                                        else
                                        {
                                                SetClipPath(&c->PoLine);
                                                PS_closepath();
                                                if (!c->strokePattern().isEmpty())
                                                        HandleStrokePattern(c);
                                                else if (c->GrTypeStroke > 0)
                                                        HandleGradientFillStroke(c, gcr);
                                                else if (c->lineColor() != CommonStrings::None)
                                                        putColor(c->lineColor(), c->lineShade(), false);
                                        }
                                }
                                else
                                {
                                        multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        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(&c->PoLine);
                                                        PS_closepath();
                                                        putColor(ml[it].Color, ml[it].Shade, false);
                                                }
                                        }
                                }
                        }
                        break;
                case PageItem::PolyLine:
                case PageItem::Spiral:
                        if ((c->fillColor() != CommonStrings::None) || (c->GrType != 0))
                        {
                                SetClipPath(&c->PoLine);
                                PS_closepath();
                                fillRule = c->fillRule;
                                if (c->GrType != 0)
                                        HandleGradientFillStroke(c, gcr, false);
                                else
                                        putColor(c->fillColor(), c->fillShade(), true);
                                PS_newpath();
                        }
                        if ((c->lineColor() != CommonStrings::None) || (!c->NamedLStyle.isEmpty()) || (!c->strokePattern().isEmpty()) || (c->GrTypeStroke > 0))
                        {
                                if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
                                {
                                        if ((!c->strokePattern().isEmpty()) && (c->patternStrokePath))
                                        {
                                                QPainterPath path = c->PoLine.toQPainterPath(false);
                                                HandleBrushPattern(c, path, a, PNr, sep, farb, ic, gcr, master);
                                        }
                                        else
                                        {
                                                SetClipPath(&c->PoLine, false);
                                                if (!c->strokePattern().isEmpty())
                                                        HandleStrokePattern(c);
                                                else if (c->GrTypeStroke > 0)
                                                        HandleGradientFillStroke(c, gcr);
                                                else if (c->lineColor() != CommonStrings::None)
                                                        putColor(c->lineColor(), c->lineShade(), false);
                                        }
                                }
                                else
                                {
                                        multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                        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(&c->PoLine, false);
                                                        putColor(ml[it].Color, ml[it].Shade, false);
                                                }
                                        }
                                }
                        }
                        if (c->startArrowIndex() != 0)
                        {
                                FPoint Start = c->PoLine.point(0);
                                for (int xx = 1; xx < c->PoLine.size(); xx += 2)
                                {
                                        FPoint Vector = c->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(c->startArrowScale() / 100.0, c->startArrowScale() / 100.0);
                                                drawArrow(c, arrowTrans, c->startArrowIndex(), gcr);
                                                break;
                                        }
                                }
                        }
                        if (c->endArrowIndex() != 0)
                        {
                                FPoint End = c->PoLine.point(c->PoLine.size()-2);
                                for (uint xx = c->PoLine.size()-1; xx > 0; xx -= 2)
                                {
                                        FPoint Vector = c->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(c->endArrowScale() / 100.0, c->endArrowScale() / 100.0);
                                                drawArrow(c, arrowTrans, c->endArrowIndex(), gcr);
                                                break;
                                        }
                                }
                        }
                        break;
                case PageItem::PathText:
                        if (master)
                                break;
                        if (c->PoShow)
                        {
                                if (c->PoLine.size() > 3)
                                {
                                        PS_save();
                                        if (c->NamedLStyle.isEmpty()) //&& (c->lineWidth() != 0.0))
                                        {
                                                if ((!c->strokePattern().isEmpty()) && (c->patternStrokePath))
                                                {
                                                        QPainterPath path = c->PoLine.toQPainterPath(false);
                                                        HandleBrushPattern(c, path, a, PNr, sep, farb, ic, gcr, master);
                                                }
                                                else
                                                {
                                                        SetClipPath(&c->PoLine, false);
                                                        if (!c->strokePattern().isEmpty())
                                                                HandleStrokePattern(c);
                                                        else if (c->GrTypeStroke > 0)
                                                                HandleGradientFillStroke(c, gcr);
                                                        else if (c->lineColor() != CommonStrings::None)
                                                                putColor(c->lineColor(), c->lineShade(), false);
                                                }
                                        }
                                        else
                                        {
                                                multiLine ml = Doc->MLineStyles[c->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, gcr);
                                                                PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                                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(&c->PoLine, false);
                                                                putColor(ml[it].Color, ml[it].Shade, false);
                                                        }
                                                }
                                        }
                                        PS_restore();
                                }
                        }
                        savedOwnPage = c->OwnPage;
                        c->OwnPage = PNr-1;
                        c->asPathText()->layout();
                        c->OwnPage = savedOwnPage;
                        for (d = 0; d < c->maxCharsInFrame(); ++d)
                        {
                hl = c->asPathText()->itemRenderText.item_p(d);
                                const CharStyle & style(c->asPathText()->itemRenderText.charStyle(d));
                                if ((hl->ch == QChar(13)) || (hl->ch == QChar(30)) || (hl->ch == QChar(9)) || (hl->ch == QChar(28)))
                                        continue;
                                QPointF tangt = QPointF( cos(hl->PRot), sin(hl->PRot) );
                                tsz = style.fontSize();
                                chstr = hl->ch;
                                if (hl->ch == QChar(29))
                                        chstr = ' ';
                                if (hl->ch == QChar(0xA0))
                                        chstr = ' ';
                                if (style.effects() & 32)
                                {
                                        if (chstr.toUpper() != chstr)
                                                chstr = chstr.toUpper();
                                }
                                if (style.effects() & 64)
                                {
                                        if (chstr.toUpper() != chstr)
                                        {
                                                tsz = style.fontSize() * Doc->typographicPrefs().valueSmallCaps / 100;
                                                chstr = chstr.toUpper();
                                        }
                                }
                                if (style.effects() & 1)
                                        tsz = style.fontSize() * Doc->typographicPrefs().scalingSuperScript / 100;
                                if (style.effects() & 2)
                                        tsz = style.fontSize() * Doc->typographicPrefs().scalingSubScript / 100;
                                if (style.fillColor() != CommonStrings::None)
                                {
                                        SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k, gcr);
                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                }
                                if (hl->hasObject(Doc))
                                {
                                        PS_save();
                                        PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -hl->PDx, 0.0) + "\n");
                                        if (c->textPathFlipped)
                                        {
                                                PutStream("[1 0 0 -1 0 0]\n");
                                                PutStream("[0 0 0  0 0 0] concatmatrix\n"); //???????
                                        }
                                        if (c->textPathType == 0)
                                                PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), hl->PtransX, -hl->PtransY) + "\n");
                                        else if (c->textPathType == 1)
                                                PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                        else if (c->textPathType == 2)
                                        {
                                                double a = 1;
                                                double b = -1;
                                                if (tangt.x()< 0)
                                                {
                                                        a = -1;
                                                        b = 1;
                                                }
                                                if (fabs(tangt.x()) > 0.1)
                                                        PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                                else
                                                        PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                        }
                                        PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
//                                      PS_translate(0, (tsz / 10.0));
                                        if (c->BaseOffs != 0)
                                                PS_translate(0, -c->BaseOffs);
                                        if (style.scaleH() != 1000)
                                                PS_scale(style.scaleH() / 1000.0, 1);
                                        QList<PageItem*> emG = hl->getGroupedItems(Doc);
                                        for (int em = 0; em < emG.count(); ++em)
                                        {
                                                PageItem* embedded = emG.at(em);
                                                PS_save();
                                                PS_translate(embedded->gXpos * (style.scaleH() / 1000.0), ((embedded->gHeight * (style.scaleV() / 1000.0)) - embedded->gYpos * (style.scaleV() / 1000.0)));
                                                if (style.baselineOffset() != 0)
                                                        PS_translate(0, embedded->gHeight * (style.baselineOffset() / 1000.0));
                                                if (style.scaleH() != 1000)
                                                        PS_scale(style.scaleH() / 1000.0, 1);
                                                if (style.scaleV() != 1000)
                                                        PS_scale(1, style.scaleV() / 1000.0);
                                                ProcessItem(Doc, a, embedded, PNr, sep, farb, ic, gcr, master, true);
                                                PS_restore();
                                        }
                                        PS_restore();
                                        continue;
                                }
                                /* Subset all TTF Fonts until the bug in the TTF-Embedding Code is fixed */
                                if (FontSubsetMap.contains(style.font().scName()))
                                {
//                                      uint chr = chstr.unicode();
                                        uint chr = style.font().char2CMap(chstr);
                                        if (style.font().canRender(chstr))
                                        {
                                                PS_save();
                                                if (style.fillColor() != CommonStrings::None)
                                                {
                                                        PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -hl->PDx, 0.0) + "\n");
                                                        if (c->textPathFlipped)
                                                        {
                                                                PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
                                                                PutStream("[0.0 0.0 0.0  0.0 0.0 0.0] concatmatrix\n");
                                                        }
                                                        if (c->textPathType == 0)
                                                                PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), hl->PtransX, -hl->PtransY) + "\n");
                                                        else if (c->textPathType == 1)
                                                                PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                                        else if (c->textPathType == 2)
                                                        {
                                                                double a = 1;
                                                                double b = -1;
                                                                if (tangt.x() < 0)
                                                                {
                                                                        a = -1;
                                                                        b = 1;
                                                                }
                                                                if (fabs(tangt.x()) > 0.1)
                                                                        PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                                                else
                                                                        PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                                        }
                                                        PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
                                                        PS_translate(0, (tsz / 10.0));
                                                        if (c->BaseOffs != 0)
                                                                PS_translate(0, -c->BaseOffs);
                                                        if (hl->glyph.xoffset !=0 || hl->glyph.yoffset != 0)
                                                                PS_translate(hl->glyph.xoffset, -hl->glyph.yoffset);
                                                        if (style.scaleH() != 1000)
                                                                PS_scale(style.scaleH() / 1000.0, 1);
                                                        if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))  
                                                                || ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
                                                        {
                                                                PS_save();
                                                                PS_translate(0, -(tsz / 10.0));
                                                                double Ulen = hl->glyph.xadvance;
                                                                double Upos, Uwid;
                                                                if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
                                                                {
                                                                        if (style.underlineOffset() != -1)
                                                                                Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
                                                                        else
                                                                                Upos = style.font().underlinePos(style.fontSize() / 10.0);
                                                                        if (style.underlineWidth() != -1)
                                                                                Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
                                                                        else
                                                                                Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                                }
                                                                else
                                                                {
                                                                        Upos = style.font().underlinePos(style.fontSize() / 10.0);
                                                                        Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                                }
                                                                if (style.baselineOffset() != 0)
                                                                        Upos += (style.fontSize() / 10.0) * hl->glyph.scaleV * (style.baselineOffset() / 1000.0);
                                                                if (style.fillColor() != CommonStrings::None)
                                                                {
                                                                        SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k, gcr);
                                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                                }
                                                                PS_setlinewidth(Uwid);
                                                                if (style.effects() & ScStyle_Subscript)
                                                                {
                                                                        PS_moveto(hl->glyph.xoffset     , Upos);
                                                                        PS_lineto(hl->glyph.xoffset+Ulen, Upos);
                                                                }
                                                                else
                                                                {
                                                                        PS_moveto(hl->glyph.xoffset     , hl->glyph.yoffset+Upos);
                                                                        PS_lineto(hl->glyph.xoffset+Ulen, hl->glyph.yoffset+Upos);
                                                                }
                                                                putColor(style.fillColor(), style.fillShade(), false);
                                                                PS_restore();
                                                        }
                                                        if (chstr != ' ')
                                                        {
                                                                if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
                                                                {
                                                                        PS_save();
                                                                        PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
                                                                        putColorNoDraw(style.strokeColor(), style.strokeShade(), gcr);
                                                                        PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
                                                                        PS_restore();
                                                                }
                                                                putColorNoDraw(style.fillColor(), style.fillShade(), gcr);
                                                                PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, false);
                                                                if ((style.effects() & ScStyle_Outline))
                                                                {
                                                                        if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
                                                                        {
                                                                                PS_save();
                                                                                PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
                                                                                putColorNoDraw(style.strokeColor(), style.strokeShade(), gcr);
                                                                                PS_showSub(chr, FontSubsetMap[style.font().scName()], tsz / 10.0, true);
                                                                                PS_restore();
                                                                        }
                                                                }
                                                        }
                                                        if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
                                                        {
                                                                PS_save();
                                                                PS_translate(0, -(tsz / 10.0));
                                                                double Ulen = hl->glyph.xadvance;
                                                                double Upos, Uwid;
                                                                if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
                                                                {
                                                                        if (style.strikethruOffset() != -1)
                                                                                Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
                                                                        else
                                                                                Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
                                                                        if (style.strikethruWidth() != -1)
                                                                                Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
                                                                        else
                                                                                Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                                }
                                                                else
                                                                {
                                                                        Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
                                                                        Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                                }
                                                                if (style.baselineOffset() != 0)
                                                                        Upos += (style.fontSize() / 10.0) * hl->glyph.scaleV * (style.baselineOffset() / 1000.0);
                                                                if (style.fillColor() != CommonStrings::None)
                                                                {
                                                                        SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k, gcr);
                                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                                }
                                                                PS_setlinewidth(Uwid);
                                                                PS_moveto(hl->glyph.xoffset     , Upos);
                                                                PS_lineto(hl->glyph.xoffset+Ulen, Upos);
                                                                putColor(style.fillColor(), style.fillShade(), false);
                                                                PS_restore();
                                                        }
                                                }
                                                PS_restore();
                                        }
                                }
                                else
                                {
                                        uint glyph = hl->glyph.glyph;
                                        PS_selectfont(style.font().replacementName(), tsz / 10.0);
                                        PS_save();
                                        PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, -hl->PDx, 0.0) + "\n");
                                        if (c->textPathFlipped)
                                        {
                                                PutStream("[1.0 0.0 0.0 -1.0 0.0 0.0]\n");
                                                PutStream("[0.0 0.0 0.0  0.0 0.0 0.0] concatmatrix\n");
                                        }
                                        if (c->textPathType == 0)
                                                PutStream( MatrixToStr(tangt.x(), -tangt.y(), -tangt.y(), -tangt.x(), hl->PtransX, -hl->PtransY) + "\n");
                                        else if (c->textPathType == 1)
                                                PutStream( MatrixToStr(1.0, 0.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                        else if (c->textPathType == 2)
                                        {
                                                double a = 1;
                                                double b = -1;
                                                if (tangt.x() < 0)
                                                {
                                                        a = -1;
                                                        b = 1;
                                                }
                                                if (fabs(tangt.x()) > 0.1)
                                                        PutStream( MatrixToStr(a, (tangt.y() / tangt.x()) * b, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                                else
                                                        PutStream( MatrixToStr(a, 4.0, 0.0, -1.0, hl->PtransX, -hl->PtransY) + "\n");
                                        }
                                        PutStream("[0.0 0.0 0.0 0.0 0.0 0.0] concatmatrix\nconcat\n");
                                        if (c->BaseOffs != 0)
                                                PS_translate(0, -c->BaseOffs);
                                        if (hl->glyph.xoffset !=0 || hl->glyph.yoffset != 0)
                                                PS_translate(hl->glyph.xoffset, -hl->glyph.yoffset);
                                        if (((style.effects() & ScStyle_Underline) && !SpecialChars::isBreak(chstr)) //FIXME && (chstr != QChar(13)))  
                                                || ((style.effects() & ScStyle_UnderlineWords) && !chstr.isSpace() && !SpecialChars::isBreak(chstr)))
                                        {
                                                PS_save();
                                                double Ulen = hl->glyph.xadvance;
                                                double Upos, Uwid;
                                                if ((style.underlineOffset() != -1) || (style.underlineWidth() != -1))
                                                {
                                                        if (style.underlineOffset() != -1)
                                                                Upos = (style.underlineOffset() / 1000.0) * (style.font().descent(style.fontSize() / 10.0));
                                                        else
                                                                Upos = style.font().underlinePos(style.fontSize() / 10.0);
                                                        if (style.underlineWidth() != -1)
                                                                Uwid = (style.underlineWidth() / 1000.0) * (style.fontSize() / 10.0);
                                                        else
                                                                Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                }
                                                else
                                                {
                                                        Upos = style.font().underlinePos(style.fontSize() / 10.0);
                                                        Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                }
                                                if (style.baselineOffset() != 0)
                                                        Upos += (style.fontSize() / 10.0) * hl->glyph.scaleV * (style.baselineOffset() / 1000.0);
                                                if (style.fillColor() != CommonStrings::None)
                                                {
                                                        SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                }
                                                PS_setlinewidth(Uwid);
                                                if (style.effects() & ScStyle_Subscript)
                                                {
                                                        PS_moveto(hl->glyph.xoffset     , Upos);
                                                        PS_lineto(hl->glyph.xoffset+Ulen, Upos);
                                                }
                                                else
                                                {
                                                        PS_moveto(hl->glyph.xoffset     , hl->glyph.yoffset+Upos);
                                                        PS_lineto(hl->glyph.xoffset+Ulen, hl->glyph.yoffset+Upos);
                                                }
                                                putColor(style.fillColor(), style.fillShade(), false);
                                                PS_restore();
                                        }
                                        if (chstr != ' ')
                                        {
                                                if ((style.effects() & ScStyle_Shadowed) && (style.strokeColor() != CommonStrings::None))
                                                {
                                                        PS_save();
                                                        PS_translate(style.fontSize() * style.shadowXOffset() / 10000.0, style.fontSize() * style.shadowYOffset() / 10000.0);
                                                        PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.strokeColor(), style.strokeShade());
                                                        PS_restore();
                                                }
                                                PS_show_xyG(style.font().replacementName(), glyph, 0, 0, style.fillColor(), style.fillShade());
                                                if ((style.effects() & ScStyle_Outline))
                                                {
                                                        if ((style.strokeColor() != CommonStrings::None) && ((tsz * style.outlineWidth() / 10000.0) != 0))
                                                        {
                                                                uint gl = style.font().char2CMap(chstr);
                                                                FPointArray gly = style.font().glyphOutline(gl);
                                                                QTransform chma;
                                                                chma.scale(tsz / 100.0, tsz / 100.0);
                                                                gly.map(chma);
                                                                PS_save();
                                                                PS_setlinewidth(tsz * style.outlineWidth() / 10000.0);
                                                                PS_translate(0,  tsz / 10.0);
                                                                SetColor(style.strokeColor(), style.strokeShade(), &h, &s, &v, &k, gcr);
                                                                PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                                SetClipPath(&gly);
                                                                PS_closepath();
                                                                putColor(style.strokeColor(), style.strokeShade(), false);
                                                                PS_restore();
                                                        }
                                                }
                                        }
                                        if ((style.effects() & ScStyle_Strikethrough) && (chstr != SpecialChars::PARSEP))
                                        {
                                                PS_save();
                                                double Ulen = hl->glyph.xadvance;
                                                double Upos, Uwid;
                                                if ((style.strikethruOffset() != -1) || (style.strikethruWidth() != -1))
                                                {
                                                        if (style.strikethruOffset() != -1)
                                                                Upos = (style.strikethruOffset() / 1000.0) * (style.font().ascent(style.fontSize() / 10.0));
                                                        else
                                                                Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
                                                        if (style.strikethruWidth() != -1)
                                                                Uwid = (style.strikethruWidth() / 1000.0) * (style.fontSize() / 10.0);
                                                        else
                                                                Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                }
                                                else
                                                {
                                                        Upos = style.font().strikeoutPos(style.fontSize() / 10.0);
                                                        Uwid = qMax(style.font().strokeWidth(style.fontSize() / 10.0), 1.0);
                                                }
                                                if (style.baselineOffset() != 0)
                                                        Upos += (style.fontSize() / 10.0) * hl->glyph.scaleV * (style.baselineOffset() / 1000.0);
                                                if (style.fillColor() != CommonStrings::None)
                                                if (style.fillColor() != CommonStrings::None)
                                                {
                                                        SetColor(style.fillColor(), style.fillShade(), &h, &s, &v, &k, gcr);
                                                        PS_setcmykcolor_stroke(h / 255.0, s / 255.0, v / 255.0, k / 255.0);
                                                }
                                                PS_setlinewidth(Uwid);
                                                PS_moveto(hl->glyph.xoffset     , Upos);
                                                PS_lineto(hl->glyph.xoffset+Ulen, Upos);
                                                putColor(style.fillColor(), style.fillShade(), false);
                                                PS_restore();
                                        }
                                        PS_restore();
                                }
                        }
                        break;
                case PageItem::Symbol:
                        if (m_Doc->docPatterns.contains(c->pattern()))
                        {
                                ScPattern pat = m_Doc->docPatterns[c->pattern()];
                                PS_save();
                                SetClipPath(&c->PoLine);
                                PS_closepath();
                                PS_clip(c->fillRule);
                                if (c->imageFlippedH())
                                {
                                        PS_translate(c->width(), 0);
                                        PS_scale(-1, 1);
                                }
                                if (c->imageFlippedV())
                                {
                                        PS_translate(0, -c->height());
                                        PS_scale(1, -1);
                                }
                                PS_scale(c->width() / pat.width, c->height() / pat.height);
                                PS_translate(0, -c->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, c->height() - embed->gYpos);
                                        ProcessItem(m_Doc, a, embed, PNr, sep, farb, ic, gcr, master, true);
                                        PS_restore();
                                }
                                PS_restore();
                        }
                        break;
                case PageItem::Group:
                        PS_save();
                        SetClipPath(&c->PoLine);
                        PS_closepath();
                        PS_clip(c->fillRule);
                        if (c->imageFlippedH())
                        {
                                PS_translate(c->width(), 0);
                                PS_scale(-1, 1);
                        }
                        if (c->imageFlippedV())
                        {
                                PS_translate(0, -c->height());
                                PS_scale(1, -1);
                        }
                        PS_scale(c->width() / c->groupWidth, c->height() / c->groupHeight);
                        PS_translate(0, -c->height());
                        for (int em = 0; em < c->groupItemList.count(); ++em)
                        {
                                PageItem* embed = c->groupItemList.at(em);
                                PS_save();
                                PS_translate(embed->gXpos, c->height() - embed->gYpos);
                                ProcessItem(m_Doc, a, embed, PNr, sep, farb, ic, gcr, master, true);
                                PS_restore();
                        }
                        PS_restore();
                        break;
                case PageItem::Table:
                        if (master)
                                break;
                        PS_save();
                        PS_translate(c->asTable()->gridOffset().x(), -c->asTable()->gridOffset().y());
                        // Paint table fill.
                        if (c->asTable()->fillColor() != CommonStrings::None)
                        {
                                int lastCol = c->asTable()->columns() - 1;
                                int lastRow = c->asTable()->rows() - 1;
                                double x = c->asTable()->columnPosition(0);
                                double y = c->asTable()->rowPosition(0);
                                double width = c->asTable()->columnPosition(lastCol) + c->asTable()->columnWidth(lastCol) - x;
                                double height = c->asTable()->rowPosition(lastRow) + c->asTable()->rowHeight(lastRow) - y;
                                putColorNoDraw(c->asTable()->fillColor(), c->asTable()->fillShade(), gcr);
                                PutStream("0 0 "+ToStr(width)+" "+ToStr(-height)+" rectfill\n");
                        }
                        // Pass 1: Paint cell fills.
                        for (int row = 0; row < c->asTable()->rows(); ++row)
                        {
                                int colSpan = 0;
                                for (int col = 0; col < c->asTable()->columns(); col += colSpan)
                                {
                                        TableCell cell = c->asTable()->cellAt(row, col);
                                        if (row == cell.row())
                                        {
                                                QString colorName = cell.fillColor();
                                                if (colorName != CommonStrings::None)
                                                {
                                                        PS_save();
                                                        putColorNoDraw(colorName, cell.fillShade(), gcr);
                                                        int row = cell.row();
                                                        int col = cell.column();
                                                        int lastRow = row + cell.rowSpan() - 1;
                                                        int lastCol = col + cell.columnSpan() - 1;
                                                        double x = c->asTable()->columnPosition(col);
                                                        double y = c->asTable()->rowPosition(row);
                                                        double width = c->asTable()->columnPosition(lastCol) + c->asTable()->columnWidth(lastCol) - x;
                                                        double height = c->asTable()->rowPosition(lastRow) + c->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 < c->asTable()->rows(); ++row)
                        {
                                int colSpan = 0;
                                for (int col = 0; col < c->asTable()->columns(); col += colSpan)
                                {
                                        TableCell cell = c->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 = c->asTable()->columnPosition(lastCol) + c->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 = c->asTable()->cellAt(row, lastCol + 1);
                                                        startRow = qMax(cell.row(), rightCell.row());
                                                        endRow = qMin(lastRow, rightCell.isValid() ? rightCell.row() + rightCell.rowSpan() - 1 : lastRow);
                                                        TableCell topLeftCell = c->asTable()->cellAt(startRow - 1, lastCol);
                                                        TableCell topRightCell = c->asTable()->cellAt(startRow - 1, lastCol + 1);
                                                        TableCell bottomRightCell = c->asTable()->cellAt(endRow + 1, lastCol + 1);
                                                        TableCell bottomLeftCell = c->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, c->asTable());
                                                        if (border.isNull())
                                                                continue; // Quit early if the border to paint is null.
                                                        start.setY(c->asTable()->rowPosition(startRow));
                                                        end.setY((c->asTable()->rowPosition(endRow) + c->asTable()->rowHeight(endRow)));
                                                        joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
                                                        paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, gcr);
                                                }
                                                if (col == 0)
                                                {
                                                        const int lastRow = cell.row() + cell.rowSpan() - 1;
                                                        const int firstCol = cell.column();
                                                        const double borderX = c->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 = c->asTable()->cellAt(row, firstCol - 1);
                                                                startRow = qMax(cell.row(), leftCell.row());
                                                                endRow = qMin(lastRow, leftCell.isValid() ? leftCell.row() + leftCell.rowSpan() - 1 : lastRow);
                                                                TableCell topLeftCell = c->asTable()->cellAt(startRow - 1, firstCol - 1);
                                                                TableCell topRightCell = c->asTable()->cellAt(startRow - 1, firstCol);
                                                                TableCell bottomRightCell = c->asTable()->cellAt(lastRow + 1, firstCol);
                                                                TableCell bottomLeftCell = c->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, c->asTable());
                                                                if (border.isNull())
                                                                        continue; // Quit early if the border to paint is null.
                                                                start.setY(c->asTable()->rowPosition(startRow));
                                                                end.setY((c->asTable()->rowPosition(endRow) + c->asTable()->rowHeight(endRow)));
                                                                joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
                                                                paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, gcr);
                                                        }
                                                }
                                        }
                                        colSpan = cell.columnSpan();
                                }
                        }
                        // Pass 3: Paint horizontal borders.
                        for (int row = 0; row < c->asTable()->rows(); ++row)
                        {
                                int colSpan = 0;
                                for (int col = 0; col < c->asTable()->columns(); col += colSpan)
                                {
                                        TableCell cell = c->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 = (c->asTable()->rowPosition(lastRow) + c->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 = c->asTable()->cellAt(lastRow + 1, col);
                                                        startCol = qMax(cell.column(), bottomCell.column());
                                                        endCol = qMin(lastCol, bottomCell.isValid() ? bottomCell.column() + bottomCell.columnSpan() - 1 : lastCol);
                                                        TableCell topLeftCell = c->asTable()->cellAt(lastRow, startCol - 1);
                                                        TableCell topRightCell = c->asTable()->cellAt(lastRow, endCol + 1);
                                                        TableCell bottomRightCell = c->asTable()->cellAt(lastRow + 1, endCol + 1);
                                                        TableCell bottomLeftCell = c->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, c->asTable());
                                                        if (border.isNull())
                                                                continue; // Quit early if the border is null.
                                                        start.setX(c->asTable()->columnPosition(startCol));
                                                        end.setX(c->asTable()->columnPosition(endCol) + c->asTable()->columnWidth(endCol));
                                                        joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
                                                        paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, gcr);
                                                }
                                                if (row == 0)
                                                {
                                                        const int firstRow = cell.row();
                                                        const int lastCol = cell.column() + cell.columnSpan() - 1;
                                                        const double borderY = c->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 = c->asTable()->cellAt(firstRow - 1, col);
                                                                startCol = qMax(cell.column(), topCell.column());
                                                                endCol = qMin(lastCol, topCell.isValid() ? topCell.column() + topCell.columnSpan() - 1 : lastCol);
                                                                TableCell topLeftCell = c->asTable()->cellAt(firstRow - 1, startCol - 1);
                                                                TableCell topRightCell = c->asTable()->cellAt(firstRow - 1, endCol + 1);
                                                                TableCell bottomRightCell = c->asTable()->cellAt(firstRow, endCol + 1);
                                                                TableCell bottomLeftCell = c->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, c->asTable());
                                                                if (border.isNull())
                                                                        continue; // Quit early if the border is null.
                                                                start.setX(c->asTable()->columnPosition(startCol));
                                                                end.setX(c->asTable()->columnPosition(endCol) + c->asTable()->columnWidth(endCol));
                                                                joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
                                                                paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, gcr);
                                                        }
                                                }
                                        }
                                        colSpan = cell.columnSpan();
                                }
                        }
                        // Pass 4: Paint cell content.
                        for (int row = 0; row < c->asTable()->rows(); ++row)
                        {
                                for (int col = 0; col < c->asTable()->columns(); col ++)
                                {
                                        TableCell cell = c->asTable()->cellAt(row, col);
                                        if (cell.row() == row && cell.column() == col)
  &