Subversion Repositories Scribus

Rev

Rev 24665 | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/


#include "slaoutput.h"

#include <poppler/GlobalParams.h>
#include <poppler/poppler-config.h>
#include <poppler/FileSpec.h>
#include <poppler/fofi/FoFiTrueType.h>
#include <QApplication>
#include <QFile>
#include "commonstrings.h"
#include "loadsaveplugin.h"
#include "sccolorengine.h"
#include "util.h"
#include "util_math.h"
#include <tiffio.h>

//#ifndef DEBUG_TEXT_IMPORT
//      #define DEBUG_TEXT_IMPORT
//#endif

namespace
{
        // Compute the intersection of two paths while considering the fillrule of each of them.
        // QPainterPath has the right interface to do the operation but is currently buggy.
        // See for example https://bugreports.qt.io/browse/QTBUG-83102. Thus this function
        // applies some heuristics to find the best result. As soon QPainterPath is fixed
        // one can just use a.intersected(b) wherever this function is called.
        // TODO: Find an alternative to QPainterPath that works for different fill rules.
        QPainterPath intersection(QPainterPath const &a, QPainterPath const &b)
        {
                // An empty path is treated like the whole area.
                if (a.elementCount() == 0)
                        return b;
                if (b.elementCount() == 0)
                        return a;

                QPainterPath ret_a = a.intersected(b);
                QPainterPath ret_b = b.intersected(a);
                // Sometimes the resulting paths are not closed even though they should.
                // Close them now.
                ret_a.closeSubpath();
                ret_b.closeSubpath();

                // Most of the time one of the two operations returns an empty path while the other
                // gives us the desired result. Return the non-empty one.
                if (ret_a.elementCount() == 0)
                        return ret_b;
                if (ret_b.elementCount() == 0)
                        return ret_a;

                // There are cases where both intersections are not empty but one of them is quite
                // complicated with several subpaths, etc. We return the simpler one.
                return (ret_a.elementCount() <= ret_b.elementCount()) ? ret_a : ret_b;
        }

        // Invert preblending matte values into the color values. Assuming that c and alpha are RGBA components
        // between 0 and 255.
        int unblendMatte(int c, int alpha, int matte)
        {
                if (alpha == 0)
                        return matte;
                int ret = matte + ((c - matte) * 255) / alpha;
                if (ret < 0)
                        return 0;
                if (ret > 255)
                        return 255;
                return ret;
        }
}

LinkSubmitForm::LinkSubmitForm(Object *actionObj)
{
        if (!actionObj->isDict())
                return;

        Object obj1 = actionObj->dictLookup("F");
        if (!obj1.isNull())
        {
                if (obj1.isDict())
                {
                        Object obj3 = obj1.dictLookup("FS");
                        if (!obj3.isNull())
                        {
                                if (obj3.isName())
                                {
                                        POPPLER_CONST char *name = obj3.getName();
                                        if (!strcmp(name, "URL"))
                                        {
                                                Object obj2 = obj1.dictLookup("F");
                                                if (!obj2.isNull())
                                                        fileName = obj2.getString()->copy();
                                        }
                                }
                        }
                }
        }
        obj1 = actionObj->dictLookup("Flags");
        if (!obj1.isNull())
        {
                if (obj1.isNum())
                        m_flags = obj1.getInt();
        }
}

LinkSubmitForm::~LinkSubmitForm()
{
        delete fileName;
}

LinkImportData::LinkImportData(Object *actionObj)
{
        if (!actionObj->isDict())
                return;
        Object obj1 = actionObj->dictLookup("F");
        if (obj1.isNull())
                return;

        Object obj3 = getFileSpecNameForPlatform(&obj1);
        if (!obj3.isNull())
                fileName = obj3.getString()->copy();
}

LinkImportData::~LinkImportData()
{
        delete fileName;
}

AnoOutputDev::~AnoOutputDev()
{
        delete fontName;
        delete itemText;
}

AnoOutputDev::AnoOutputDev(ScribusDoc* doc, QStringList *importedColors)
{
        m_doc = doc;
        m_importedColors = importedColors;
        currColorText = "Black";
        currColorFill = CommonStrings::None;
        currColorStroke = CommonStrings::None;
}

void AnoOutputDev::eoFill(GfxState *state)
{
        int shade = 100;
        currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
}

void AnoOutputDev::fill(GfxState *state)
{
        int shade = 100;
        currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
}

void AnoOutputDev::stroke(GfxState *state)
{
        int shade = 100;
        currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &shade);
}

void AnoOutputDev::drawString(GfxState *state, POPPLER_CONST GooString *s)
{
        int shade = 100;
        currColorText = getColor(state->getFillColorSpace(), state->getFillColor(), &shade);
        fontSize = state->getFontSize();
        if (state->getFont())
                fontName = state->getFont()->getName()->copy();
        itemText = s->copy();
}

QString AnoOutputDev::getColor(GfxColorSpace *color_space, POPPLER_CONST_070 GfxColor *color, int *shade)
{
        QString fNam;
        QString namPrefix = "FromPDF";
        ScColor tmp;
        tmp.setSpotColor(false);
        tmp.setRegistrationColor(false);
        *shade = 100;
        if ((color_space->getMode() == csDeviceRGB) || (color_space->getMode() == csCalRGB))
        {
                GfxRGB rgb;
                color_space->getRGB(color, &rgb);
                double Rc = colToDbl(rgb.r);
                double Gc = colToDbl(rgb.g);
                double Bc = colToDbl(rgb.b);
                tmp.setRgbColorF(Rc, Gc, Bc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if (color_space->getMode() == csDeviceCMYK)
        {
                GfxCMYK cmyk;
                color_space->getCMYK(color, &cmyk);
                double Cc = colToDbl(cmyk.c);
                double Mc = colToDbl(cmyk.m);
                double Yc = colToDbl(cmyk.y);
                double Kc = colToDbl(cmyk.k);
                tmp.setCmykColorF(Cc, Mc, Yc, Kc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if ((color_space->getMode() == csCalGray) || (color_space->getMode() == csDeviceGray))
        {
                GfxGray gray;
                color_space->getGray(color, &gray);
                double Kc = 1.0 - colToDbl(gray);
                tmp.setCmykColorF(0, 0, 0, Kc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if (color_space->getMode() == csSeparation)
        {
                GfxSeparationColorSpace* sepColorSpace = (GfxSeparationColorSpace*)color_space;
                GfxColorSpace* altColorSpace = sepColorSpace->getAlt();
                QString name = QString(sepColorSpace->getName()->getCString());
                bool isRegistrationColor = (name == "All");
                if (isRegistrationColor)
                {
                        tmp.setCmykColorF(1.0, 1.0, 1.0, 1.0);
                        tmp.setRegistrationColor(true);
                        name = "Registration";
                }
                else if ((altColorSpace->getMode() == csDeviceRGB) || (altColorSpace->getMode() == csCalRGB))
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setRgbColorF(comps[0], comps[1], comps[2]);
                }
                else if ((altColorSpace->getMode() == csCalGray) || (altColorSpace->getMode() == csDeviceGray))
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setCmykColorF(0.0, 0.0, 0.0, 1.0 - comps[0]);
                }
                else if (altColorSpace->getMode() == csLab)
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setLabColor(comps[0], comps[1], comps[2]);
                }
                else
                {
                        GfxCMYK cmyk;
                        color_space->getCMYK(color, &cmyk);
                        double Cc = colToDbl(cmyk.c);
                        double Mc = colToDbl(cmyk.m);
                        double Yc = colToDbl(cmyk.y);
                        double Kc = colToDbl(cmyk.k);
                        tmp.setCmykColorF(Cc, Mc, Yc, Kc);
                }
                tmp.setSpotColor(true);

                fNam = m_doc->PageColors.tryAddColor(name, tmp);
                *shade = qRound(colToDbl(color->c[0]) * 100);
        }
        else
        {
                GfxRGB rgb;
                color_space->getRGB(color, &rgb);
                double Rc = colToDbl(rgb.r);
                double Gc = colToDbl(rgb.g);
                double Bc = colToDbl(rgb.b);
                tmp.setRgbColorF(Rc, Gc, Bc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        //      qDebug() << "update fill color other colorspace" << color_space->getMode() << "treating as rgb" << Rc << Gc << Bc;
        }
        if (fNam == namPrefix+tmp.name())
                m_importedColors->append(fNam);
        return fNam;
}

SlaOutputDev::SlaOutputDev(ScribusDoc* doc, QList<PageItem*> *Elements, QStringList *importedColors, int flags)
{
        m_doc = doc;
        m_Elements = Elements;
        pushGroup();
        m_importedColors = importedColors;
        m_currColorStroke = "Black";
        m_currColorFill = "Black";
        tmpSel = new Selection(m_doc, false);
        importerFlags = flags;
        currentLayer = m_doc->activeLayer();
        layersSetByOCG = false;
}

SlaOutputDev::~SlaOutputDev()
{
        m_groupStack.clear();
        tmpSel->clear();
        delete tmpSel;
        delete m_fontEngine;
}

/* get Actions not implemented by Poppler */
LinkAction* SlaOutputDev::SC_getAction(AnnotWidget *ano)
{
        LinkAction *linkAction = nullptr;
        Object obj;
        Ref refa = ano->getRef();

        obj = xref->fetch(refa.num, refa.gen);
        if (obj.isDict())
        {
                Dict* adic = obj.getDict();
                POPPLER_CONST_075 Object POPPLER_REF additionalActions = adic->lookupNF("A");
                Object additionalActionsObject = additionalActions.fetch(pdfDoc->getXRef());
                if (additionalActionsObject.isDict())
                {
                        Object actionObject = additionalActionsObject.dictLookup("S");
                        if (actionObject.isName("ImportData"))
                        {
                                linkAction = new LinkImportData(&additionalActionsObject);
                        }
                        else if (actionObject.isName("SubmitForm"))
                        {
                                linkAction = new LinkSubmitForm(&additionalActionsObject);
                        }
                }
        }
        return linkAction;
}

/* Replacement for the crippled Poppler function LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type) */
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
std::unique_ptr<LinkAction> SlaOutputDev::SC_getAdditionalAction(const char *key, AnnotWidget *ano)
{
        std::unique_ptr<LinkAction> linkAction;
#else
LinkAction* SlaOutputDev::SC_getAdditionalAction(const char *key, AnnotWidget *ano)
{
        LinkAction *linkAction = nullptr;
#endif
        Object obj;
        Ref refa = ano->getRef();

        obj = xref->fetch(refa.num, refa.gen);
        if (obj.isDict())
        {
                Dict* adic = obj.getDict();
                POPPLER_CONST_075 Object POPPLER_REF additionalActions = adic->lookupNF("AA");
                Object additionalActionsObject = additionalActions.fetch(pdfDoc->getXRef());
                if (additionalActionsObject.isDict())
                {
                        Object actionObject = additionalActionsObject.dictLookup(key);
                        if (actionObject.isDict())
                                linkAction = LinkAction::parseAction(&actionObject, pdfDoc->getCatalog()->getBaseURI());
                }
        }
        return linkAction;
}

GBool SlaOutputDev::annotations_callback(Annot *annota, void *user_data)
{
        SlaOutputDev *dev = (SlaOutputDev*)user_data;
        PDFRectangle *box = annota->getRect();
        double xCoor = dev->m_doc->currentPage()->xOffset() + box->x1 - dev->cropOffsetX;
        double yCoor = dev->m_doc->currentPage()->yOffset() + dev->m_doc->currentPage()->height() - box->y2 + dev->cropOffsetY;
        double width = box->x2 - box->x1;
        double height = box->y2 - box->y1;
        if (dev->rotate == 90)
        {
                xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + box->y2;
                yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + box->x1;
        }
        else if (dev->rotate == 180)
        {
                xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + dev->m_doc->currentPage()->width() - box->x1;
                yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + box->y2;
        }
        else if (dev->rotate == 270)
        {
                xCoor = dev->m_doc->currentPage()->xOffset() - dev->cropOffsetX + dev->m_doc->currentPage()->width() - box->y2;
                yCoor = dev->m_doc->currentPage()->yOffset() + dev->cropOffsetY + dev->m_doc->currentPage()->height() - box->x1;
        }
        bool retVal = true;
        if (annota->getType() == Annot::typeText)
                retVal = !dev->handleTextAnnot(annota, xCoor, yCoor, width, height);
        else if (annota->getType() == Annot::typeLink)
                retVal = !dev->handleLinkAnnot(annota, xCoor, yCoor, width, height);
        else if (annota->getType() == Annot::typeWidget)
                retVal = !dev->handleWidgetAnnot(annota, xCoor, yCoor, width, height);
        return retVal;
}

bool SlaOutputDev::handleTextAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
{
        AnnotText *anl = (AnnotText*)annota;
        int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, CommonStrings::None, CommonStrings::None);
        PageItem *ite = m_doc->Items->at(z);
        int flg = annota->getFlags();
        if (!(flg & 16))
                ite->setRotation(rotate, true);
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillEvenOdd(false);
        ite->Clip = flattenPath(ite->PoLine, ite->Segments);
        ite->ContourLine = ite->PoLine.copy();
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        ite->setIsAnnotation(true);
        ite->AutoName = false;
        ite->annotation().setType(Annotation::Text);
        ite->annotation().setActionType(Annotation::Action_None);
        ite->annotation().setAnOpen(anl->getOpen());
        QString iconName = UnicodeParsedString(anl->getIcon());
        if (iconName == "Note")
                ite->annotation().setIcon(Annotation::Icon_Note);
        else if (iconName == "Comment")
                ite->annotation().setIcon(Annotation::Icon_Comment);
        else if (iconName == "Key")
                ite->annotation().setIcon(Annotation::Icon_Key);
        else if (iconName == "Help")
                ite->annotation().setIcon(Annotation::Icon_Help);
        else if (iconName == "NewParagraph")
                ite->annotation().setIcon(Annotation::Icon_NewParagraph);
        else if (iconName == "Paragraph")
                ite->annotation().setIcon(Annotation::Icon_Paragraph);
        else if (iconName == "Insert")
                ite->annotation().setIcon(Annotation::Icon_Insert);
        else if (iconName == "Cross")
                ite->annotation().setIcon(Annotation::Icon_Cross);
        else if (iconName == "Circle")
                ite->annotation().setIcon(Annotation::Icon_Circle);
        else
                ite->annotation().setIcon(Annotation::Icon_Note);
        ite->setItemName( CommonStrings::itemName_TextAnnotation + QString("%1").arg(m_doc->TotalItems));
        ite->itemText.insertChars(UnicodeParsedString(annota->getContents()));
        ite->itemText.trim();
        return true;
}

bool SlaOutputDev::handleLinkAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
{
        AnnotLink *anl = (AnnotLink*)annota;
        LinkAction *act = anl->getAction();
        if (!act)
                return false;
        bool validLink = false;
        int pagNum = 0;
        int xco = 0;
        int yco = 0;
        QString fileName = "";
        if (act->getKind() == actionGoTo)
        {
                LinkGoTo *gto = (LinkGoTo*) act;
                POPPLER_CONST LinkDest *dst = gto->getDest();
                if (dst)
                {
                        if (dst->getKind() == destXYZ)
                        {
                                if (dst->isPageRef())
                                {
                                        Ref dstr = dst->getPageRef();
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
                                        pagNum = pdfDoc->findPage(dstr);
#else
                                        pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
#endif
                                }
                                else
                                        pagNum = dst->getPageNum();
                                xco = dst->getLeft();
                                yco = dst->getTop();
                                validLink = true;
                        }
                }
                else
                {
                        POPPLER_CONST GooString *ndst = gto->getNamedDest();
                        if (ndst)
                        {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                                std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
#else
                                LinkDest *dstn = pdfDoc->findDest(ndst);
#endif
                                if (dstn)
                                {
                                        if (dstn->getKind() == destXYZ)
                                        {
                                                if (dstn->isPageRef())
                                                {
                                                        Ref dstr = dstn->getPageRef();
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
                                                        pagNum = pdfDoc->findPage(dstr);
#else
                                                        pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
#endif
                                                }
                                                else
                                                        pagNum = dstn->getPageNum();
                                                xco = dstn->getLeft();
                                                yco = dstn->getTop();
                                                validLink = true;
                                        }
                                }
                        }
                }
        }
        else if (act->getKind() == actionGoToR)
        {
                LinkGoToR *gto = (LinkGoToR*)act;
                fileName = UnicodeParsedString(gto->getFileName());
                POPPLER_CONST LinkDest *dst = gto->getDest();
                if (dst)
                {
                        if (dst->getKind() == destXYZ)
                        {
                                pagNum = dst->getPageNum();
                                xco = dst->getLeft();
                                yco = dst->getTop();
                                validLink = true;
                        }
                }
                else
                {
                        POPPLER_CONST GooString *ndst = gto->getNamedDest();
                        if (ndst)
                        {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                                std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
#else
                                LinkDest *dstn = pdfDoc->findDest(ndst);
#endif
                                if (dstn)
                                {
                                        if (dstn->getKind() == destXYZ)
                                        {
                                                pagNum = dstn->getPageNum();
                                                xco = dstn->getLeft();
                                                yco = dstn->getTop();
                                                validLink = true;
                                        }
                                }
                        }
                }
        }
        else if (act->getKind() == actionURI)
        {
                LinkURI *gto = (LinkURI*)act;
                validLink = true;
                fileName = UnicodeParsedString(gto->getURI());
        }
        if (validLink)
        {
                int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, CommonStrings::None, CommonStrings::None);
                PageItem *ite = m_doc->Items->at(z);
                int flg = annota->getFlags();
                if (!(flg & 16))
                        ite->setRotation(rotate, true);
                ite->ClipEdited = true;
                ite->FrameType = 3;
                ite->setFillEvenOdd(false);
                ite->Clip = flattenPath(ite->PoLine, ite->Segments);
                ite->ContourLine = ite->PoLine.copy();
                ite->setTextFlowMode(PageItem::TextFlowDisabled);
                m_Elements->append(ite);
                if (m_groupStack.count() != 0)
                {
                        m_groupStack.top().Items.append(ite);
                        applyMask(ite);
                }
                ite->setIsAnnotation(true);
                ite->AutoName = false;
                if (act->getKind() == actionGoTo)
                {
                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                        ite->annotation().setActionType(2);
                }
                else if (act->getKind() == actionGoToR)
                {
                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                        ite->annotation().setExtern(fileName);
                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                        ite->annotation().setActionType(9);
                }
                else if (act->getKind() == actionURI)
                {
                        ite->annotation().setAction("");
                        ite->annotation().setExtern(fileName);
                        ite->annotation().setActionType(8);
                }
                ite->annotation().setType(Annotation::Link);
                ite->setItemName( CommonStrings::itemName_LinkAnnotation + QString("%1").arg(m_doc->TotalItems));
        }
        return validLink;
}

bool SlaOutputDev::handleWidgetAnnot(Annot* annota, double xCoor, double yCoor, double width, double height)
{
        bool retVal = false;
        bool found = false;

        if (!m_formWidgets)
                return false;

        int formcount = m_formWidgets->getNumWidgets();
        for (int i = 0; i < formcount; ++i)
        {
                FormWidget *fm = m_formWidgets->getWidget(i);
                if (!fm)
                        continue;
                AnnotWidget *ano = fm->getWidgetAnnotation();
                if (!ano)
                        continue;
                if (ano != (AnnotWidget*) annota)
                        continue;
                found = true;
                int wtyp = -1;
                if (fm->getType() == formButton)
                {
                        FormWidgetButton *btn = (FormWidgetButton*)fm;
                        if (btn)
                        {
                                if (btn->getButtonType() == formButtonCheck)
                                {
                                        wtyp = Annotation::Checkbox;
                                        retVal = true;
                                }
                                else if (btn->getButtonType() == formButtonPush)
                                {
                                        wtyp = Annotation::Button;
                                        retVal = true;
                                }
                                else if (btn->getButtonType() == formButtonRadio)
                                {
                                        wtyp = Annotation::RadioButton;
                                        retVal = true;
                                }
                        }
                }
                else if (fm->getType() == formText)
                {
                        wtyp = Annotation::Textfield;
                        retVal = true;
                }
                else if (fm->getType() == formChoice)
                {
                        FormWidgetChoice *btn = (FormWidgetChoice*)fm;
                        if (btn)
                        {
                                if (btn->isCombo())
                                {
                                        wtyp = Annotation::Combobox;
                                        retVal = true;
                                }
                                else if (btn->isListBox())
                                {
                                        wtyp = Annotation::Listbox;
                                        retVal = true;
                                }
                        }
                }
                if (retVal)
                {
                        AnnotAppearanceCharacs *achar = ano->getAppearCharacs();
                        bool fgFound = false;
                        bool bgFound = false;
                        if (achar)
                        {
                                POPPLER_CONST AnnotColor *bgCol = achar->getBackColor();
                                if (bgCol)
                                {
                                        bgFound = true;
                                        m_currColorFill = getAnnotationColor(bgCol);
                                }
                                else
                                        m_currColorFill = CommonStrings::None;
                                POPPLER_CONST AnnotColor *fgCol = achar->getBorderColor();
                                if (fgCol)
                                {
                                        fgFound = true;
                                        m_currColorStroke = getAnnotationColor(fgCol);
                                }
                                else
                                {
                                        fgCol = achar->getBackColor();
                                        if (fgCol)
                                                m_currColorStroke = getAnnotationColor(fgCol);
                                        else
                                                m_currColorStroke = CommonStrings::None;
                                }
                        }
                        QString m_currColorText = "Black";
                        double fontSize = 12;
                        QString fontName = "";
                        QString itemText = "";
                        AnnotAppearance *apa = annota->getAppearStreams();
                        if (apa || !achar)
                        {
                                AnoOutputDev *annotOutDev = new AnoOutputDev(m_doc, m_importedColors);
                                Gfx *gfx = new Gfx(pdfDoc, annotOutDev, pdfDoc->getPage(m_actPage)->getResourceDict(), annota->getRect(), nullptr);
                                ano->draw(gfx, false);
                                if (!bgFound)
                                        m_currColorFill = annotOutDev->currColorFill;
                                if (!fgFound)
                                        m_currColorStroke = annotOutDev->currColorStroke;
                                m_currColorText = annotOutDev->currColorText;
                                fontSize = annotOutDev->fontSize;
                                fontName = UnicodeParsedString(annotOutDev->fontName);
                                itemText = UnicodeParsedString(annotOutDev->itemText);
                                delete gfx;
                                delete annotOutDev;
                        }
                        int z = m_doc->itemAdd(PageItem::TextFrame, PageItem::Rectangle, xCoor, yCoor, width, height, 0, m_currColorFill, CommonStrings::None);
                        PageItem *ite = m_doc->Items->at(z);
                        int flg = annota->getFlags();
                        if (!(flg & 16))
                                ite->setRotation(rotate, true);
                        ite->ClipEdited = true;
                        ite->FrameType = 3;
                        ite->setFillEvenOdd(false);
                        ite->Clip = flattenPath(ite->PoLine, ite->Segments);
                        ite->ContourLine = ite->PoLine.copy();
                        ite->setTextFlowMode(PageItem::TextFlowDisabled);
                        m_Elements->append(ite);
                        if (m_groupStack.count() != 0)
                        {
                                m_groupStack.top().Items.append(ite);
                                applyMask(ite);
                        }
                        ite->setIsAnnotation(true);
                        ite->AutoName = false;
                        AnnotBorder *brd = annota->getBorder();
                        if (brd)
                        {
                                int bsty = brd->getStyle();
                                if (bsty == AnnotBorder::borderDashed)
                                        bsty = 1;
                                else if (bsty == AnnotBorder::borderBeveled)
                                        bsty = 3;
                                else if (bsty == AnnotBorder::borderInset)
                                        bsty = 4;
                                else if (bsty == AnnotBorder::borderUnderlined)
                                        bsty = 2;
                                ite->annotation().setBorderStyle(bsty);
                                ite->annotation().setBorderColor(m_currColorStroke);
                                ite->annotation().setBorderWidth(qRound(brd->getWidth()));
                        }
                        else
                        {
                                ite->annotation().setBorderStyle(0);
                                ite->annotation().setBorderColor(CommonStrings::None);
                                ite->annotation().setBorderWidth(0);
                        }
                        QString tmTxt = "";
                        tmTxt = UnicodeParsedString(fm->getPartialName());
                        if (!tmTxt.isEmpty())
                                ite->setItemName(tmTxt);
                        tmTxt = "";
                        tmTxt = UnicodeParsedString(fm->getAlternateUiName());
                        if (!tmTxt.isEmpty())
                                ite->annotation().setToolTip(tmTxt);
                        tmTxt = "";
                        if (achar)
                        {
                                tmTxt = UnicodeParsedString(achar->getRolloverCaption());
                                if (!tmTxt.isEmpty())
                                        ite->annotation().setRollOver(tmTxt);
                                tmTxt = "";
                                tmTxt = UnicodeParsedString(achar->getAlternateCaption());
                                if (!tmTxt.isEmpty())
                                        ite->annotation().setDown(tmTxt);
                        }
                        ite->annotation().setType(wtyp);
                        ite->annotation().setFlag(0);
                        if (flg & 2)
                                ite->annotation().setVis(1);
                        if (flg & 32)
                                ite->annotation().setVis(3);
                        if (wtyp == Annotation::Button)
                        {
                                ite->setFillColor(m_currColorFill);
                                if (achar)
                                        ite->itemText.insertChars(UnicodeParsedString(achar->getNormalCaption()));
                                else
                                        ite->itemText.insertChars(itemText);
                                applyTextStyle(ite, fontName, m_currColorText, fontSize);
                                ite->annotation().addToFlag(Annotation::Flag_PushButton);
                                FormWidgetButton *btn = (FormWidgetButton*)fm;
                                if (!btn->isReadOnly())
                                        ite->annotation().addToFlag(Annotation::Flag_Edit);
                                handleActions(ite, ano);
                        }
                        else if (wtyp == Annotation::Textfield)
                        {
                                FormWidgetText *btn = (FormWidgetText*)fm;
                                if (btn)
                                {
                                        ite->itemText.insertChars(UnicodeParsedString(btn->getContent()));
                                        applyTextStyle(ite, fontName, m_currColorText, fontSize);
                                        ite->itemText.trim();
                                        if (btn->isMultiline())
                                                ite->annotation().addToFlag(Annotation::Flag_Multiline);
                                        if (btn->isPassword())
                                                ite->annotation().addToFlag(Annotation::Flag_Password);
                                        if (btn->noSpellCheck())
                                                ite->annotation().addToFlag(Annotation::Flag_DoNotSpellCheck);
                                        if (btn->noScroll())
                                                ite->annotation().addToFlag(Annotation::Flag_DoNotScroll);
                                        int mxLen = btn->getMaxLen();
                                        if (mxLen > 0)
                                                ite->annotation().setMaxChar(mxLen);
                                        else
                                                ite->annotation().setMaxChar(-1);
                                        if (!btn->isReadOnly())
                                                ite->annotation().addToFlag(Annotation::Flag_Edit);
                                        handleActions(ite, ano);
                                }
                        }
                        else if (wtyp == Annotation::Checkbox)
                        {
                                FormWidgetButton *btn = (FormWidgetButton*)fm;
                                if (btn)
                                {
                                        ite->annotation().setIsChk(btn->getState());
                                        ite->annotation().setCheckState(ite->annotation().IsChk());
                                        handleActions(ite, ano);
                                        if (itemText == "4")
                                                ite->annotation().setChkStil(0);
                                        else if (itemText == "5")
                                                ite->annotation().setChkStil(1);
                                        else if (itemText == "F")
                                                ite->annotation().setChkStil(2);
                                        else if (itemText == "l")
                                                ite->annotation().setChkStil(3);
                                        else if (itemText == "H")
                                                ite->annotation().setChkStil(4);
                                        else if (itemText == "n")
                                                ite->annotation().setChkStil(5);
                                        else
                                                ite->annotation().setChkStil(0);
                                        if (!btn->isReadOnly())
                                                ite->annotation().addToFlag(Annotation::Flag_Edit);
                                }
                        }
                        else if ((wtyp == Annotation::Combobox) || (wtyp == Annotation::Listbox))
                        {
                                FormWidgetChoice *btn = (FormWidgetChoice*)fm;
                                if (btn)
                                {
                                        if (wtyp == 5)
                                                ite->annotation().addToFlag(Annotation::Flag_Combo);
                                        int co = btn->getNumChoices();
                                        if (co > 0)
                                        {
                                                QString inh = UnicodeParsedString(btn->getChoice(0));
                                                for (int a = 1; a < co; a++)
                                                {
                                                        inh += "\n" + UnicodeParsedString(btn->getChoice(a));
                                                }
                                                ite->itemText.insertChars(inh);
                                        }
                                        applyTextStyle(ite, fontName, m_currColorText, fontSize);
                                        if (!btn->isReadOnly())
                                                ite->annotation().addToFlag(Annotation::Flag_Edit);
                                        handleActions(ite, ano);
                                }
                        }
                        else if (wtyp == Annotation::RadioButton)
                        {
                                FormWidgetButton *btn = (FormWidgetButton*)fm;
                                if (btn)
                                {
                                        ite->setItemName( CommonStrings::itemName_RadioButton + QString("%1").arg(m_doc->TotalItems));
                                        ite->annotation().setIsChk(btn->getState());
                                        ite->annotation().setCheckState(ite->annotation().IsChk());
                                        handleActions(ite, ano);
                                        m_radioButtons.insert(annota->getRef().num, ite);
                                }
                        }
                }
                break;
        }
        if (!found)
        {
                Object obj1;
                Ref refa = annota->getRef();
                obj1 = xref->fetch(refa.num, refa.gen);
                if (obj1.isDict())
                {
                        Dict* dict = obj1.getDict();
                        Object obj2 = dict->lookup("Kids");
                        //childs
                        if (obj2.isArray())
                        {
                                // Load children
                                QList<int> radList;
                                for (int i = 0; i < obj2.arrayGetLength(); i++)
                                {
                                        POPPLER_CONST_075 Object POPPLER_REF childRef = obj2.arrayGetNF(i);
                                        if (!childRef.isRef())
                                                continue;
                                        Object childObj = obj2.arrayGet(i);
                                        if (!childObj.isDict())
                                                continue;
                                        const Ref ref = childRef.getRef();
                                        radList.append(ref.num);
                                }
                                QString tmTxt = UnicodeParsedString(annota->getName());
                                m_radioMap.insert(tmTxt, radList);
                        }
                }
        }
        return retVal;
}

void SlaOutputDev::applyTextStyle(PageItem* ite, const QString& fontName, const QString& textColor, double fontSize)
{
        CharStyle newStyle;
        newStyle.setFillColor(textColor);
        newStyle.setFontSize(fontSize * 10);
        if (!fontName.isEmpty())
        {
                SCFontsIterator it(*m_doc->AllFonts);
                for ( ; it.hasNext() ; it.next())
                {
                        ScFace& face(it.current());
                        if ((face.psName() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
                        {
                                newStyle.setFont(face);
                                break;
                        }
                        if ((face.family() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
                        {
                                newStyle.setFont(face);
                                break;
                        }
                        if ((face.scName() == fontName) && (face.usable()) && (face.type() == ScFace::TTF))
                        {
                                newStyle.setFont(face);
                                break;
                        }
                }
        }
        ParagraphStyle dstyle(ite->itemText.defaultStyle());
        dstyle.charStyle().applyCharStyle(newStyle);
        ite->itemText.setDefaultStyle(dstyle);
        ite->itemText.applyCharStyle(0, ite->itemText.length(), newStyle);
        ite->invalid = true;
}

void SlaOutputDev::handleActions(PageItem* ite, AnnotWidget *ano)
{
        LinkAction *Lact = ano->getAction();
        if (Lact)
        {
                if (Lact->getKind() == actionJavaScript)
                {
                        LinkJavaScript *jsa = (LinkJavaScript*)Lact;
                        if (jsa->isOk())
                        {
                                ite->annotation().setActionType(1);
                                ite->annotation().setAction(UnicodeParsedString(jsa->getScript()));
                        }
                }
                else if (Lact->getKind() == actionGoTo)
                {
                        int pagNum = 0;
                        int xco = 0;
                        int yco = 0;
                        LinkGoTo *gto = (LinkGoTo*)Lact;
                        POPPLER_CONST LinkDest *dst = gto->getDest();
                        if (dst)
                        {
                                if (dst->getKind() == destXYZ)
                                {
                                        if (dst->isPageRef())
                                        {
                                                Ref dstr = dst->getPageRef();
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
                                                pagNum = pdfDoc->findPage(dstr);
#else
                                                pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
#endif
                                        }
                                        else
                                                pagNum = dst->getPageNum();
                                        xco = dst->getLeft();
                                        yco = dst->getTop();
                                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                                        ite->annotation().setActionType(2);
                                }
                        }
                        else
                        {
                                POPPLER_CONST GooString *ndst = gto->getNamedDest();
                                if (ndst)
                                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                                        std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
#else
                                        LinkDest *dstn = pdfDoc->findDest(ndst);
#endif
                                        if (dstn)
                                        {
                                                if (dstn->getKind() == destXYZ)
                                                {
                                                        if (dstn->isPageRef())
                                                        {
                                                                Ref dstr = dstn->getPageRef();
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 76, 0)
                                                                pagNum = pdfDoc->findPage(dstr);
#else
                                                                pagNum = pdfDoc->findPage(dstr.num, dstr.gen);
#endif
                                                        }
                                                        else
                                                                pagNum = dstn->getPageNum();
                                                        xco = dstn->getLeft();
                                                        yco = dstn->getTop();
                                                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                                                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                                                        ite->annotation().setActionType(2);
                                                }
                                        }
                                }
                        }
                }
                else if (Lact->getKind() == actionGoToR)
                {
                        int pagNum = 0;
                        int xco = 0;
                        int yco = 0;
                        LinkGoToR *gto = (LinkGoToR*)Lact;
                        QString fileName = UnicodeParsedString(gto->getFileName());
                        POPPLER_CONST LinkDest *dst = gto->getDest();
                        if (dst)
                        {
                                if (dst->getKind() == destXYZ)
                                {
                                        pagNum = dst->getPageNum();
                                        xco = dst->getLeft();
                                        yco = dst->getTop();
                                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                                        ite->annotation().setExtern(fileName);
                                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                                        ite->annotation().setActionType(9);
                                }
                        }
                        else
                        {
                                POPPLER_CONST GooString *ndst = gto->getNamedDest();
                                if (ndst)
                                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                                        std::unique_ptr<LinkDest> dstn = pdfDoc->findDest(ndst);
#else
                                        LinkDest *dstn = pdfDoc->findDest(ndst);
#endif
                                        if (dstn)
                                        {
                                                if (dstn->getKind() == destXYZ)
                                                {
                                                        pagNum = dstn->getPageNum();
                                                        xco = dstn->getLeft();
                                                        yco = dstn->getTop();
                                                        ite->annotation().setZiel((pagNum > 0) ? (pagNum - 1) : (m_actPage - 1));
                                                        ite->annotation().setExtern(fileName);
                                                        ite->annotation().setAction(QString("%1 %2").arg(xco).arg(yco));
                                                        ite->annotation().setActionType(9);
                                                }
                                        }
                                }
                        }
                }
                else if (Lact->getKind() == actionUnknown)
                {
                        LinkUnknown *uno = (LinkUnknown*)Lact;
                        QString actString = UnicodeParsedString(uno->getAction());
                        if (actString == "ResetForm")
                        {
                                ite->annotation().setActionType(4);
                        }
                        else
                        {
                                LinkAction* scact = SC_getAction(ano);
                                if (scact)
                                {
                                        if (actString == "ImportData")
                                        {
                                                LinkImportData *impo = (LinkImportData*)scact;
                                                if (impo->isOk())
                                                {
                                                        ite->annotation().setActionType(5);
                                                        ite->annotation().setAction(UnicodeParsedString(impo->getFileName()));
                                                }
                                        }
                                        else if (actString == "SubmitForm")
                                        {
                                                LinkSubmitForm *impo = (LinkSubmitForm*)scact;
                                                if (impo->isOk())
                                                {
                                                        ite->annotation().setActionType(3);
                                                        ite->annotation().setAction(UnicodeParsedString(impo->getFileName()));
                                                        int fl = impo->getFlags();
                                                        if (fl == 0)
                                                                ite->annotation().setHTML(0);
                                                        else if (fl == 4)
                                                                ite->annotation().setHTML(1);
                                                        else if (fl == 64)
                                                                ite->annotation().setHTML(2);
                                                        else if (fl == 512)
                                                                ite->annotation().setHTML(3);
                                                }
                                        }
                                }
                        }
                }
                else if (Lact->getKind() == actionNamed)
                {
                        LinkNamed *uno = (LinkNamed*)Lact;
                        ite->annotation().setActionType(10);
                        ite->annotation().setAction(UnicodeParsedString(uno->getName()));
                }
                else
                        qDebug() << "Found unsupported Action of type" << Lact->getKind();
        }
        auto Aact = SC_getAdditionalAction("D", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setD_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("E", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setE_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("X", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setX_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("Fo", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setFo_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("Bl", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setBl_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("C", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setC_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("F", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setF_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                                ite->annotation().setFormat(5);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("K", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setK_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                                ite->annotation().setFormat(5);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
        Aact = SC_getAdditionalAction("V", ano);
        if (Aact)
        {
                if (Aact->getKind() == actionJavaScript)
                {
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact.get();
#else
                        LinkJavaScript *jsa = (LinkJavaScript*) Aact;
#endif
                        if (jsa->isOk())
                        {
                                ite->annotation().setV_act(UnicodeParsedString(jsa->getScript()));
                                ite->annotation().setAAact(true);
                        }
                }
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 86, 0)
                Aact.reset();
#else
                Aact = nullptr;
#endif
        }
}

void SlaOutputDev::startDoc(PDFDoc *doc, XRef *xrefA, Catalog *catA)
{
        xref = xrefA;
        catalog = catA;
        pdfDoc = doc;
        updateGUICounter = 0;
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(0, 84, 0)
        m_fontEngine = new SplashFontEngine(true, false, false, true);
#else
        m_fontEngine = new SplashFontEngine(globalParams->getEnableFreeType(), false, false, true);
#endif
}

void SlaOutputDev::startPage(int pageNum, GfxState *, XRef *)
{
        m_formWidgets = pdfDoc->getPage(pageNum)->getFormWidgets();
        m_radioMap.clear();
        m_radioButtons.clear();
        m_actPage = pageNum;
        m_groupStack.clear();
        pushGroup();
        m_currentClipPath = QPainterPath();
        m_clipPaths.clear();
}

void SlaOutputDev::endPage()
{
        if (!m_radioMap.isEmpty())
        {
                for (auto it = m_radioMap.begin(); it != m_radioMap.end(); ++it)
                {
                        tmpSel->clear();
                        QList<int> refList = it.value();
                        for (int a = 0; a < refList.count(); a++)
                        {
                                if (m_radioButtons.contains(refList[a]))
                                {
                                        tmpSel->addItem(m_radioButtons[refList[a]], true);
                                        m_Elements->removeAll(m_radioButtons[refList[a]]);
                                }
                        }
                        if (!tmpSel->isEmpty())
                        {
                                PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
                                ite->setItemName(it.key());
                                m_Elements->append(ite);
                                if (m_groupStack.count() != 0)
                                        m_groupStack.top().Items.append(ite);
                        }
                }
        }
        m_radioMap.clear();
        m_radioButtons.clear();
//      qDebug() << "ending page";
}

void SlaOutputDev::saveState(GfxState *state)
{
        m_clipPaths.push(m_currentClipPath);
        pushGroup();
}

void SlaOutputDev::restoreState(GfxState *state)
{
        if (m_groupStack.count() != 0)
        {
                groupEntry gElements = m_groupStack.pop();
                if (gElements.Items.count() > 0)
                {
                        if ((gElements.Items.count() > 1) && (checkClip()))
                        {
                                tmpSel->clear();
                                for (int dre = 0; dre < gElements.Items.count(); ++dre)
                                {
                                        tmpSel->addItem(gElements.Items.at(dre), true);
                                        m_Elements->removeAll(gElements.Items.at(dre));
                                }
                                PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
                                if (ite)
                                {
                                        QPainterPath clippath = m_currentClipPath;
                                        clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
                                        clippath.translate(-ite->xPos(), -ite->yPos());
                                        ite->PoLine.fromQPainterPath(clippath, true);
                                        ite->ClipEdited = true;
                                        ite->FrameType = 3;
                                        ite->setTextFlowMode(PageItem::TextFlowDisabled);
                                        // Comment out temporarily, there are some bad interactions between adjustItemSize() and
                                        // resizeGroupToContents() since fixing resizing of multiple selections
                                        //m_doc->adjustItemSize(ite, true);
                                        m_doc->resizeGroupToContents(ite);
                                        ite->OldB2 = ite->width();
                                        ite->OldH2 = ite->height();
                                        m_Elements->append(ite);
                                        if (m_groupStack.count() != 0)
                                        {
                                                applyMask(ite);
                                                m_groupStack.top().Items.append(ite);
                                        }
                                }
                                else
                                {
                                        if (m_groupStack.count() != 0)
                                        {
                                                for (int dre = 0; dre < gElements.Items.count(); ++dre)
                                                {
                                                        PageItem *ite = gElements.Items.at(dre);
                                                        applyMask(ite);
                                                        m_groupStack.top().Items.append(ite);
                                                }
                                        }
                                }
                                tmpSel->clear();
                        }
                        else
                        {
                                if (m_groupStack.count() != 0)
                                {
                                        for (int dre = 0; dre < gElements.Items.count(); ++dre)
                                        {
                                                PageItem *ite = gElements.Items.at(dre);
                                                applyMask(ite);
                                                m_groupStack.top().Items.append(ite);
                                        }
                                }
                        }
                }
        }
        if (m_clipPaths.count() != 0)
                m_currentClipPath = m_clipPaths.pop();
}

void SlaOutputDev::beginTransparencyGroup(GfxState *state, POPPLER_CONST_070 double *bbox, GfxColorSpace * /*blendingColorSpace*/, GBool isolated, GBool knockout, GBool forSoftMask)
{
//      qDebug() << "SlaOutputDev::beginTransparencyGroup isolated:" << isolated << "knockout:" << knockout << "forSoftMask:" << forSoftMask;
        pushGroup("", forSoftMask);
        m_groupStack.top().isolated = isolated;
}

void SlaOutputDev::paintTransparencyGroup(GfxState *state, POPPLER_CONST_070 double *bbox)
{
//      qDebug() << "SlaOutputDev::paintTransparencyGroup";
        if (m_groupStack.count() != 0)
        {
                if ((m_groupStack.top().Items.count() != 0) && (!m_groupStack.top().forSoftMask))
                {
                        PageItem *ite = m_groupStack.top().Items.last();
                        ite->setFillTransparency(1.0 - state->getFillOpacity());
                        ite->setFillBlendmode(getBlendMode(state));
                }
        }
}

void SlaOutputDev::endTransparencyGroup(GfxState *state)
{
//      qDebug() << "SlaOutputDev::endTransparencyGroup";
        if (m_groupStack.count() <= 0)
                return;

        tmpSel->clear();

        groupEntry gElements = m_groupStack.pop();
        if (gElements.Items.count() <= 0)
                return;

        if (gElements.forSoftMask)
        {
                for (int dre = 0; dre < gElements.Items.count(); ++dre)
                {
                        tmpSel->addItem(gElements.Items.at(dre), true);
                        m_Elements->removeAll(gElements.Items.at(dre));
                }
                PageItem *ite = m_doc->groupObjectsSelection(tmpSel);
                ite->setFillTransparency(1.0 - state->getFillOpacity());
                ite->setFillBlendmode(getBlendMode(state));
                ScPattern pat(m_doc);
                m_doc->DoDrawing = true;
                pat.pattern = ite->DrawObj_toImage(qMin(qMax(ite->width(), ite->height()), 500.0));
                pat.xoffset = 0;
                pat.yoffset = 0;
                m_doc->DoDrawing = false;
                pat.width = ite->width();
                pat.height = ite->height();
                m_currentMaskPosition = QPointF(ite->xPos(), ite->yPos());
                ite->gXpos = 0;
                ite->gYpos = 0;
                ite->setXYPos(ite->gXpos, ite->gYpos, true);
                pat.items.append(ite);
                m_doc->Items->removeAll(ite);
                QString id = QString("Pattern_from_PDF_%1S").arg(m_doc->docPatterns.count() + 1);
                m_doc->addPattern(id, pat);
                m_currentMask = id;
                tmpSel->clear();
                return;
        }
        PageItem *ite;
        for (int dre = 0; dre < gElements.Items.count(); ++dre)
        {
                tmpSel->addItem(gElements.Items.at(dre), true);
                m_Elements->removeAll(gElements.Items.at(dre));
        }
        if ((gElements.Items.count() != 1) || (gElements.isolated))
                ite = m_doc->groupObjectsSelection(tmpSel);
        else
                ite = gElements.Items.first();
        if (ite->isGroup())
        {
                ite->ClipEdited = true;
                ite->FrameType = 3;
                if (checkClip())
                {
                        QPainterPath clippath = m_currentClipPath;
                        clippath.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
                        clippath.translate(-ite->xPos(), -ite->yPos());
                        ite->PoLine.fromQPainterPath(clippath, true);
                        ite->ClipEdited = true;
                        ite->FrameType = 3;
                        ite->setTextFlowMode(PageItem::TextFlowDisabled);
                        // Comment out temporarily, there are some bad interactions between adjustItemSize() and
                        // resizeGroupToContents() since fixing resizing of multiple selections
                        //m_doc->adjustItemSize(ite, true);
                        m_doc->resizeGroupToContents(ite);
                        ite->OldB2 = ite->width();
                        ite->OldH2 = ite->height();
                }
        }
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                applyMask(ite);
                m_groupStack.top().Items.append(ite);
        }

        tmpSel->clear();
}

void SlaOutputDev::setSoftMask(GfxState * /*state*/, POPPLER_CONST_070 double * bbox, GBool alpha, Function *transferFunc, GfxColor * /*backdropColor*/)
{
        if (m_groupStack.count() <= 0)
                return;

        double lum = 0;
        double lum2 = 0;
        if (transferFunc)
                transferFunc->transform(&lum, &lum2);
        else
                lum2 = lum;
        m_groupStack.top().inverted = (lum != lum2);
        m_groupStack.top().maskName = m_currentMask;
        // Remember the mask's position as it might not align with the image to which the mask is later assigned.
        m_groupStack.top().maskPos = m_currentMaskPosition;
        m_groupStack.top().alpha = alpha;
        if (m_groupStack.top().Items.count() != 0)
                applyMask(m_groupStack.top().Items.last());
}

void SlaOutputDev::clearSoftMask(GfxState * /*state*/)
{
        if (m_groupStack.count() != 0)
                m_groupStack.top().maskName = "";
}

void SlaOutputDev::updateFillColor(GfxState *state)
{
        m_currFillShade = 100;
        m_currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &m_currFillShade);
}

void SlaOutputDev::updateStrokeColor(GfxState *state)
{
        m_currStrokeShade = 100;
        m_currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &m_currStrokeShade);
}

void SlaOutputDev::clip(GfxState *state)
{
//      qDebug() << "Clip";
        adjustClip(state, Qt::WindingFill);
}

void SlaOutputDev::eoClip(GfxState *state)
{
//      qDebug() << "EoClip";
        adjustClip(state, Qt::OddEvenFill);
}

void SlaOutputDev::adjustClip(GfxState *state, Qt::FillRule fillRule)
{
        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        QString output = convertPath(state->getPath());
        if (output.isEmpty())
                return;
        FPointArray out;
        out.parseSVG(output);
        out.svgClosePath();
        out.map(m_ctm);
        if (checkClip())
        {
                // "clip" (WindingFill) and "eoClip" (OddEvenFill) only the determine
                // the fill rule of the new clipping path. The new clip should be the
                // intersection of the old and new area. QPainterPath determines on
                // its own which fill rule to use for the result. We should not loose
                // this information.
                QPainterPath pathN = out.toQPainterPath(false);
                pathN.setFillRule(fillRule);
                m_currentClipPath = intersection(pathN, m_currentClipPath);
        }
        else
                m_currentClipPath = out.toQPainterPath(false);
}

void SlaOutputDev::stroke(GfxState *state)
{
//      qDebug() << "Stroke";
        const double *ctm;
        ctm = state->getCTM();
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        QString output = convertPath(state->getPath());
        getPenState(state);
        if ((m_Elements->count() != 0) && (output == Coords))                   // Path is the same as in last fill
        {
                PageItem* ite = m_Elements->last();
                ite->setLineColor(m_currColorStroke);
                ite->setLineShade(m_currStrokeShade);
                ite->setLineEnd(m_lineEnd);
                ite->setLineJoin(m_lineJoin);
                ite->setLineWidth(state->getTransformedLineWidth());
                ite->setDashes(DashValues);
                ite->setDashOffset(DashOffset);
                ite->setLineTransparency(1.0 - state->getStrokeOpacity());
        }
        else
        {
                FPointArray out;
                out.parseSVG(output);
                m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
                out.map(m_ctm);
                FPoint wh = out.widthHeight();
                if ((out.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)))
                {
                        m_currColorStroke = getColor(state->getStrokeColorSpace(), state->getStrokeColor(), &m_currStrokeShade);
                        int z;
                        if (pathIsClosed)
                                z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, state->getTransformedLineWidth(), CommonStrings::None, m_currColorStroke);
                        else
                                z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, state->getTransformedLineWidth(), CommonStrings::None, m_currColorStroke);
                        PageItem* ite = m_doc->Items->at(z);
                        ite->PoLine = out.copy();
                        ite->ClipEdited = true;
                        ite->FrameType = 3;
                        ite->setWidthHeight(wh.x(), wh.y());
                        m_doc->adjustItemSize(ite);
                        if (m_Elements->count() != 0)
                        {
                                PageItem* lItem = m_Elements->last();
                                if ((lItem->lineColor() == CommonStrings::None) && (lItem->PoLine == ite->PoLine))
                                {
                                        lItem->setLineColor(m_currColorStroke);
                                        lItem->setLineWidth(state->getTransformedLineWidth());
                                        lItem->setLineShade(m_currStrokeShade);
                                        lItem->setLineTransparency(1.0 - state->getStrokeOpacity());
                                        lItem->setLineBlendmode(getBlendMode(state));
                                        lItem->setLineEnd(m_lineEnd);
                                        lItem->setLineJoin(m_lineJoin);
                                        lItem->setDashes(DashValues);
                                        lItem->setDashOffset(DashOffset);
                                        lItem->setTextFlowMode(PageItem::TextFlowDisabled);
                                        m_doc->Items->removeAll(ite);
                                }
                                else
                                {
                                        ite->setLineShade(m_currStrokeShade);
                                        ite->setLineTransparency(1.0 - state->getStrokeOpacity());
                                        ite->setLineBlendmode(getBlendMode(state));
                                        ite->setLineEnd(m_lineEnd);
                                        ite->setLineJoin(m_lineJoin);
                                        ite->setDashes(DashValues);
                                        ite->setDashOffset(DashOffset);
                                        ite->setTextFlowMode(PageItem::TextFlowDisabled);
                                        m_Elements->append(ite);
                                        if (m_groupStack.count() != 0)
                                                m_groupStack.top().Items.append(ite);
                                }
                        }
                        else
                        {
                                ite->setLineShade(m_currStrokeShade);
                                ite->setLineTransparency(1.0 - state->getStrokeOpacity());
                                ite->setLineBlendmode(getBlendMode(state));
                                ite->setLineEnd(m_lineEnd);
                                ite->setLineJoin(m_lineJoin);
                                ite->setDashes(DashValues);
                                ite->setDashOffset(DashOffset);
                                ite->setTextFlowMode(PageItem::TextFlowDisabled);
                                m_Elements->append(ite);
                                if (m_groupStack.count() != 0)
                                        m_groupStack.top().Items.append(ite);
                        }
                }
        }
}

void SlaOutputDev::fill(GfxState *state)
{
//      qDebug() << "Fill";
        createFillItem(state, Qt::WindingFill);
}

void SlaOutputDev::eoFill(GfxState *state)
{
//      qDebug() << "EoFill";
        createFillItem(state, Qt::OddEvenFill);
}

void SlaOutputDev::createFillItem(GfxState *state, Qt::FillRule fillRule)
{
        const double *ctm;
        ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        FPointArray out;
        QString output = convertPath(state->getPath());
        out.parseSVG(output);
        out.map(m_ctm);

        // Clip the new path first and only add it if it is not empty.
        QPainterPath path = out.toQPainterPath(false);
        path.setFillRule(fillRule);
        QPainterPath clippedPath = intersection(m_currentClipPath, path);

        // Undo the rotation of the clipping path as it is rotated together with the item.
        double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
        QTransform mm;
        mm.rotate(angle);
        clippedPath = mm.map(clippedPath);

        Coords = output;
        QRectF bbox = clippedPath.boundingRect();
        if (!clippedPath.isEmpty() && !bbox.isNull())
        {
                m_currColorFill = getColor(state->getFillColorSpace(), state->getFillColor(), &m_currFillShade);
                int z;
                if (pathIsClosed)
                        z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, m_currColorFill, CommonStrings::None);
                else
                        z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, m_currColorFill, CommonStrings::None);
                PageItem* ite = m_doc->Items->at(z);
                ite->PoLine.fromQPainterPath(clippedPath, true);
                ite->ClipEdited = true;
                ite->FrameType = 3;
                ite->setFillShade(m_currFillShade);
                ite->setLineShade(100);
                ite->setRotation(-angle);
                // Only the new path has to be interpreted according to fillRule. QPainterPath
                // could decide to create a final path according to the other rule. Thus
                // we have to set this from the final path.
                ite->setFillEvenOdd(clippedPath.fillRule() == Qt::OddEvenFill);
                ite->setFillTransparency(1.0 - state->getFillOpacity());
                ite->setFillBlendmode(getBlendMode(state));
                ite->setLineEnd(m_lineEnd);
                ite->setLineJoin(m_lineJoin);
                ite->setWidthHeight(bbox.width(),bbox.height());
                ite->setTextFlowMode(PageItem::TextFlowDisabled);
                m_doc->adjustItemSize(ite);
                m_Elements->append(ite);
                if (m_groupStack.count() != 0)
                {
                        m_groupStack.top().Items.append(ite);
                        applyMask(ite);
                }
        }
}

GBool SlaOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax)
{
//      qDebug() << "SlaOutputDev::axialShadedFill";
        double GrStartX;
        double GrStartY;
        double GrEndX;
        double GrEndY;
        int shade = 100;
        POPPLER_CONST_070 Function *func = shading->getFunc(0);
        VGradient FillGradient = VGradient(VGradient::linear);
        FillGradient.clearStops();
        GfxColorSpace *color_space = shading->getColorSpace();
        if (func->getType() == 3)
        {
                StitchingFunction *stitchingFunc = (StitchingFunction*)func;
                const double *bounds = stitchingFunc->getBounds();
                int num_funcs = stitchingFunc->getNumFuncs();
                double domain_min = stitchingFunc->getDomainMin(0);
                double domain_max = stitchingFunc->getDomainMax(0);
                if (fabs(domain_max - domain_min) < 1e-6)
                {
                        domain_min = 0.0;
                        domain_max = 1.0;
                }
                // Add stops from all the stitched functions
                for (int i = 0 ; i <= num_funcs ; i++)
                {
                        GfxColor temp;
                        shading->getColor(bounds[i], &temp);
                        QString stopColor = getColor(color_space, &temp, &shade);
                        double stopPoint = (bounds[i] - domain_min) / (domain_max - domain_min);
                        FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor], m_doc, shade), stopPoint, 0.5, 1.0, stopColor, shade );
                }
        }
        else if ((func->getType() == 2) || (func->getType() == 0))
        {
                GfxColor stop1;
                shading->getColor(0.0, &stop1);
                QString stopColor1 = getColor(color_space, &stop1, &shade);
                FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor1], m_doc, shade), 0.0, 0.5, 1.0, stopColor1, shade );
                GfxColor stop2;
                shading->getColor(1.0, &stop2);
                QString stopColor2 = getColor(color_space, &stop2, &shade);
                FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor2], m_doc, shade), 1.0, 0.5, 1.0, stopColor2, shade );
        }
        shading->getCoords(&GrStartX, &GrStartY, &GrEndX, &GrEndY);
        double xmin, ymin, xmax, ymax;
        // get the clip region bbox
        state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
        QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
        crect = crect.normalized();
        QPainterPath out;
        out.addRect(crect);
        if (checkClip())
        {
                // Apply the clip path early to adjust the gradient vector to the
                // smaller boundign box.
                out = intersection(m_currentClipPath, out);
                crect = out.boundingRect();
        }
        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        FPointArray gr;
        gr.addPoint(GrStartX, GrStartY);
        gr.addPoint(GrEndX, GrEndY);
        gr.map(m_ctm);
        gr.translate(-crect.x(), -crect.y());

        // Undo the rotation and translation of the gradient vector.
        double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
        QTransform mm;
        mm.rotate(angle);
        out.translate(-crect.x(), -crect.y());
        out = mm.map(out);
        QRectF bb = out.boundingRect();
        gr.map(mm);
        gr.translate(-bb.left(), -bb.top());
        GrStartX = gr.point(0).x();
        GrStartY = gr.point(0).y();
        GrEndX = gr.point(1).x();
        GrEndY = gr.point(1).y();

        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        QString output = QString("M %1 %2").arg(0.0).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(0.0);
        output += QString("Z");
        pathIsClosed = true;
        Coords = output;
        int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), bb.width(), bb.height(), 0, m_currColorFill, CommonStrings::None);
        PageItem* ite = m_doc->Items->at(z);
        if (checkClip())
        {
                ite->PoLine.fromQPainterPath(out, true);
                ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
        }
        ite->setRotation(-angle);
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillShade(m_currFillShade);
        ite->setLineShade(100);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        ite->setLineEnd(m_lineEnd);
        ite->setLineJoin(m_lineJoin);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        ite->GrType = 6;
        if (!shading->getExtend0() || !shading->getExtend1())
        {
                FillGradient.setRepeatMethod(VGradient::none);
                ite->setGradientExtend(VGradient::none);
        }
        else
        {
                FillGradient.setRepeatMethod(VGradient::pad);
                ite->setGradientExtend(VGradient::pad);
        }
        ite->fill_gradient = FillGradient;
        ite->setGradientVector(GrStartX, GrStartY, GrEndX, GrEndY, 0, 0, 1, 0);
        m_doc->adjustItemSize(ite);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        return gTrue;
}

GBool SlaOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax)
{
//      qDebug() << "SlaOutputDev::radialShadedFill";
        double GrStartX;
        double GrStartY;
        double GrEndX;
        double GrEndY;
        int shade = 100;
        POPPLER_CONST_070 Function *func = shading->getFunc(0);
        VGradient FillGradient = VGradient(VGradient::linear);
        FillGradient.clearStops();
        GfxColorSpace *color_space = shading->getColorSpace();
        if (func->getType() == 3)
        {
                StitchingFunction *stitchingFunc = (StitchingFunction*)func;
                const double *bounds = stitchingFunc->getBounds();
                int num_funcs = stitchingFunc->getNumFuncs();
                double domain_min = stitchingFunc->getDomainMin(0);
                double domain_max = stitchingFunc->getDomainMax(0);
                if (fabs(domain_max - domain_min) < 1e-6)
                {
                        domain_min = 0.0;
                        domain_max = 1.0;
                }
                // Add stops from all the stitched functions
                for (int i = 0 ; i <= num_funcs ; i++)
                {
                        GfxColor temp;
                        shading->getColor(bounds[i], &temp);
                        QString stopColor = getColor(color_space, &temp, &shade);
                        double stopPoint = (bounds[i] - domain_min) / (domain_max - domain_min);
                        FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor], m_doc, shade), stopPoint, 0.5, 1.0, stopColor, shade );
                }
        }
        else if ((func->getType() == 2) || (func->getType() == 0))
        {
                GfxColor stop1;
                shading->getColor(0.0, &stop1);
                QString stopColor1 = getColor(color_space, &stop1, &shade);
                FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor1], m_doc, shade), 0.0, 0.5, 1.0, stopColor1, shade );
                GfxColor stop2;
                shading->getColor(1.0, &stop2);
                QString stopColor2 = getColor(color_space, &stop2, &shade);
                FillGradient.addStop( ScColorEngine::getShadeColor(m_doc->PageColors[stopColor2], m_doc, shade), 1.0, 0.5, 1.0, stopColor2, shade );
        }
        double r0, x1, y1, r1;
        shading->getCoords(&GrStartX, &GrStartY, &r0, &x1, &y1, &r1);
        double xmin, ymin, xmax, ymax;
        // get the clip region bbox
        state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
        QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
        crect = crect.normalized();
        double GrFocalX = x1;
        double GrFocalY = y1;
        GrEndX = GrFocalX + r1;
        GrEndY = GrFocalY;
        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        FPointArray gr;
        gr.addPoint(GrStartX, GrStartY);
        gr.addPoint(GrEndX, GrEndY);
        gr.addPoint(GrFocalX, GrFocalY);
        gr.map(m_ctm);
        GrStartX = gr.point(0).x() - crect.x();
        GrStartY = gr.point(0).y() - crect.y();
        GrEndX = gr.point(1).x() - crect.x();
        GrEndY = gr.point(1).y() - crect.y();
        GrFocalX = gr.point(2).x() - crect.x();
        GrFocalY = gr.point(2).y() - crect.y();
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        QString output = QString("M %1 %2").arg(0.0).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(0.0);
        output += QString("Z");
        pathIsClosed = true;
        Coords = output;
        int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
        PageItem* ite = m_doc->Items->at(z);
        if (checkClip())
        {
                QPainterPath out = m_currentClipPath;
                out.translate(m_doc->currentPage()->xOffset(), m_doc->currentPage()->yOffset());
                out.translate(-ite->xPos(), -ite->yPos());
                ite->PoLine.fromQPainterPath(out, true);
                ite->setFillEvenOdd(out.fillRule() == Qt::OddEvenFill);
        }
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillShade(m_currFillShade);
        ite->setLineShade(100);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        ite->setLineEnd(m_lineEnd);
        ite->setLineJoin(m_lineJoin);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        ite->GrType = 7;
        if (!shading->getExtend0() || !shading->getExtend1())
        {
                FillGradient.setRepeatMethod(VGradient::none);
                ite->setGradientExtend(VGradient::none);
        }
        else
        {
                FillGradient.setRepeatMethod(VGradient::pad);
                ite->setGradientExtend(VGradient::pad);
        }
        ite->fill_gradient = FillGradient;
        ite->setGradientVector(GrStartX, GrStartY, GrEndX, GrEndY, GrFocalX, GrFocalY, 1, 0);
        m_doc->adjustItemSize(ite);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        return gTrue;
}

GBool SlaOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
{
//      qDebug() << "SlaOutputDev::gouraudTriangleShadedFill";
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        double xmin, ymin, xmax, ymax;
        // get the clip region bbox
        state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
        QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
        crect = crect.normalized();
        QString output = QString("M %1 %2").arg(0.0).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(0.0);
        output += QString("Z");
        pathIsClosed = true;
        Coords = output;
        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
        PageItem* ite = m_doc->Items->at(z);
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillShade(m_currFillShade);
        ite->setLineShade(100);
        ite->setFillEvenOdd(false);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        ite->setLineEnd(m_lineEnd);
        ite->setLineJoin(m_lineJoin);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        m_doc->adjustItemSize(ite);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        GfxColor color[3];
        double x0, y0, x1, y1, x2, y2;
        for (int i = 0; i < shading->getNTriangles(); i++)
        {
                int shade = 100;
                meshGradientPatch patchM;
                shading->getTriangle(i, &x0, &y0, &color[0],  &x1, &y1, &color[1],  &x2, &y2, &color[2]);
                patchM.BL.resetTo(FPoint(x0, y0));
                patchM.BL.shade = 100;
                patchM.BL.transparency = 1.0;
                patchM.BL.colorName = getColor(shading->getColorSpace(), &color[0], &shade);
                patchM.BL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BL.colorName], m_doc, shade);
                patchM.TL.resetTo(FPoint(x1, y1));
                patchM.TL.shade = 100;
                patchM.TL.transparency = 1.0;
                patchM.TL.colorName = getColor(shading->getColorSpace(), &color[1], &shade);
                patchM.TL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TL.colorName], m_doc, shade);
                patchM.TR.resetTo(FPoint(x2, y2));
                patchM.TR.shade = 100;
                patchM.TR.transparency = 1.0;
                patchM.TR.colorName = getColor(shading->getColorSpace(), &color[2], &shade);
                patchM.TR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TR.colorName], m_doc, shade);
                patchM.BR.resetTo(FPoint(x0, y0));
                patchM.BR.shade = 100;
                patchM.BR.transparency = 1.0;
                patchM.BR.colorName = getColor(shading->getColorSpace(), &color[0], &shade);
                patchM.BR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BR.colorName], m_doc, shade);
                patchM.TL.transform(m_ctm);
                patchM.TL.moveRel(-crect.x(), -crect.y());
                patchM.TR.transform(m_ctm);
                patchM.TR.moveRel(-crect.x(), -crect.y());
                patchM.BR.transform(m_ctm);
                patchM.BR.moveRel(-crect.x(), -crect.y());
                patchM.BL.transform(m_ctm);
                patchM.BL.moveRel(-crect.x(), -crect.y());
                ite->meshGradientPatches.append(patchM);
        }
        ite->GrType = 12;
        return gTrue;
}

GBool SlaOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
{
//      qDebug() << "SlaOutputDev::patchMeshShadedFill";
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        double xmin, ymin, xmax, ymax;
        // get the clip region bbox
        state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
        QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
        crect = crect.normalized();
        QString output = QString("M %1 %2").arg(0.0).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(0.0);
        output += QString("Z");
        pathIsClosed = true;
        Coords = output;
        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
        PageItem* ite = m_doc->Items->at(z);
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillShade(m_currFillShade);
        ite->setLineShade(100);
        ite->setFillEvenOdd(false);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        ite->setLineEnd(m_lineEnd);
        ite->setLineJoin(m_lineJoin);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        m_doc->adjustItemSize(ite);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        ite->meshGradientPatches.clear();
        for (int i = 0; i < shading->getNPatches(); i++)
        {
                int shade = 100;
                const GfxPatch *patch = shading->getPatch(i);
                GfxColor color;
                meshGradientPatch patchM;
                int u, v;
                patchM.BL.resetTo(FPoint(patch->x[0][0], patch->y[0][0]));
                patchM.BL.controlTop = FPoint(patch->x[0][1], patch->y[0][1]);
                patchM.BL.controlRight = FPoint(patch->x[1][0], patch->y[1][0]);
                patchM.BL.controlColor = FPoint(patch->x[1][1], patch->y[1][1]);
                u = 0;
                v = 0;
                if (shading->isParameterized())
                {
                        shading->getParameterizedColor (patch->color[u][v].c[0], &color);
                }
                else
                {
                        for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
                        {
                                color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
                        }
                }
                patchM.BL.colorName = getColor(shading->getColorSpace(), &color, &shade);
                patchM.BL.shade = 100;
                patchM.BL.transparency = 1.0;
                patchM.BL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BL.colorName], m_doc, shade);

                u = 0;
                v = 1;
                patchM.TL.resetTo(FPoint(patch->x[0][3], patch->y[0][3]));
                patchM.TL.controlRight = FPoint(patch->x[1][3], patch->y[1][3]);
                patchM.TL.controlBottom = FPoint(patch->x[0][2], patch->y[0][2]);
                patchM.TL.controlColor = FPoint(patch->x[1][2], patch->y[1][2]);
                if (shading->isParameterized())
                {
                        shading->getParameterizedColor (patch->color[u][v].c[0], &color);
                }
                else
                {
                        for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
                        {
                                color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
                        }
                }
                patchM.TL.colorName = getColor(shading->getColorSpace(), &color, &shade);
                patchM.TL.shade = 100;
                patchM.TL.transparency = 1.0;
                patchM.TL.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TL.colorName], m_doc, shade);

                u = 1;
                v = 1;
                patchM.TR.resetTo(FPoint(patch->x[3][3], patch->y[3][3]));
                patchM.TR.controlBottom = FPoint(patch->x[3][2], patch->y[3][2]);
                patchM.TR.controlLeft = FPoint(patch->x[2][3], patch->y[2][3]);
                patchM.TR.controlColor = FPoint(patch->x[2][2], patch->y[2][2]);
                if (shading->isParameterized())
                {
                        shading->getParameterizedColor (patch->color[u][v].c[0], &color);
                }
                else
                {
                        for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
                        {
                                color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
                        }
                }
                patchM.TR.colorName = getColor(shading->getColorSpace(), &color, &shade);
                patchM.TR.shade = 100;
                patchM.TR.transparency = 1.0;
                patchM.TR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.TR.colorName], m_doc, shade);

                u = 1;
                v = 0;
                patchM.BR.resetTo(FPoint(patch->x[3][0], patch->y[3][0]));
                patchM.BR.controlLeft = FPoint(patch->x[2][0], patch->y[2][0]);
                patchM.BR.controlTop = FPoint(patch->x[3][1], patch->y[3][1]);
                patchM.BR.controlColor = FPoint(patch->x[2][1], patch->y[2][1]);
                if (shading->isParameterized())
                {
                        shading->getParameterizedColor (patch->color[u][v].c[0], &color);
                }
                else
                {
                        for (int k = 0; k < shading->getColorSpace()->getNComps(); k++)
                        {
                                color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
                        }
                }
                patchM.BR.colorName = getColor(shading->getColorSpace(), &color, &shade);
                patchM.BR.shade = 100;
                patchM.BR.transparency = 1.0;
                patchM.BR.color = ScColorEngine::getShadeColorProof(m_doc->PageColors[patchM.BR.colorName], m_doc, shade);

                patchM.TL.transform(m_ctm);
                patchM.TL.moveRel(-crect.x(), -crect.y());
                patchM.TR.transform(m_ctm);
                patchM.TR.moveRel(-crect.x(), -crect.y());
                patchM.BR.transform(m_ctm);
                patchM.BR.moveRel(-crect.x(), -crect.y());
                patchM.BL.transform(m_ctm);
                patchM.BL.moveRel(-crect.x(), -crect.y());
                ite->meshGradientPatches.append(patchM);
        }
        ite->GrType = 12;
        return gTrue;
}

#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
bool SlaOutputDev::tilingPatternFill(GfxState *state, Gfx * /*gfx*/, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep)
#else
GBool SlaOutputDev::tilingPatternFill(GfxState *state, Gfx * /*gfx*/, Catalog *cat, Object *str, POPPLER_CONST_070 double *pmat, int /*paintType*/, int /*tilingType*/, Dict *resDict, POPPLER_CONST_070 double *mat, POPPLER_CONST_070 double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep)
#endif
{
//      qDebug() << "SlaOutputDev::tilingPatternFill";
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
        const double *bbox = tPat->getBBox();
        const double *pmat = tPat->getMatrix();
        Dict *resDict = tPat->getResDict();
#endif

        PDFRectangle box;
        Gfx *gfx;
        QString id;
        PageItem *ite;
        groupEntry gElements;
        m_groupStack.push(gElements);
        double width, height;
        width = bbox[2] - bbox[0];
        height = bbox[3] - bbox[1];
        if (xStep != width || yStep != height)
                return gFalse;
        box.x1 = bbox[0];
        box.y1 = bbox[1];
        box.x2 = bbox[2];
        box.y2 = bbox[3];

        const double *ctm = state->getCTM();
        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        QTransform mm = QTransform(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
        QTransform mmx = mm * m_ctm;

        gfx = new Gfx(pdfDoc, this, resDict, &box, nullptr);
        inPattern++;
        // Unset the clip path as it is unrelated to the pattern's coordinate space.
        QPainterPath savedClip = m_currentClipPath;
        m_currentClipPath = QPainterPath();
#if POPPLER_ENCODED_VERSION >= POPPLER_VERSION_ENCODE(21, 3, 0)
        gfx->display(tPat->getContentStream());
#else
        gfx->display(str);
#endif
        m_currentClipPath = savedClip;
        inPattern--;
        gElements = m_groupStack.pop();
        m_doc->m_Selection->clear();
//      double pwidth = 0;
//      double pheight = 0;
        if (gElements.Items.count() > 0)
        {
                for (int dre = 0; dre < gElements.Items.count(); ++dre)
                {
                        m_doc->m_Selection->addItem(gElements.Items.at(dre), true);
                        m_Elements->removeAll(gElements.Items.at(dre));
                }
                m_doc->itemSelection_FlipV();
                PageItem *ite;
                if (m_doc->m_Selection->count() > 1)
                        ite = m_doc->groupObjectsSelection();
                else
                        ite = m_doc->m_Selection->itemAt(0);
                ite->setFillTransparency(1.0 - state->getFillOpacity());
                ite->setFillBlendmode(getBlendMode(state));
                m_doc->m_Selection->clear();
                m_doc->DoDrawing = true;
                ScPattern pat(m_doc);
                pat.pattern = ite->DrawObj_toImage(qMin(qMax(ite->width(), ite->height()), 500.0));
                pat.xoffset = 0;
                pat.yoffset = 0;
                m_doc->DoDrawing = false;
                pat.width = ite->width();
                pat.height = ite->height();
        //      pwidth = ite->width();
        //      pheight = ite->height();
                ite->gXpos = 0;
                ite->gYpos = 0;
                ite->setXYPos(ite->gXpos, ite->gYpos, true);
                pat.items.append(ite);
                m_doc->Items->removeAll(ite);
                id = QString("Pattern_from_PDF_%1").arg(m_doc->docPatterns.count() + 1);
                m_doc->addPattern(id, pat);
        }
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();
        double xmin, ymin, xmax, ymax;
        // get the clip region bbox
        state->getClipBBox(&xmin, &ymin, &xmax, &ymax);
        QRectF crect = QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
        crect = crect.normalized();
        QString output = QString("M %1 %2").arg(0.0).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(0.0);
        output += QString("L %1 %2").arg(crect.width()).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(crect.height());
        output += QString("L %1 %2").arg(0.0).arg(0.0);
        output += QString("Z");
        pathIsClosed = true;
        Coords = output;
        int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, xCoor + crect.x(), yCoor + crect.y(), crect.width(), crect.height(), 0, m_currColorFill, CommonStrings::None);
        ite = m_doc->Items->at(z);

        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
        ite->setRotation(-angle);
        if (checkClip())
        {
                QPainterPath outline = m_currentClipPath;
                outline.translate(xCoor - ite->xPos(), yCoor - ite->yPos());
                // Undo the rotation of the clipping path as it is rotated together with the item.
                QTransform mm;
                mm.rotate(angle);
                outline = mm.map(outline);
                ite->PoLine.fromQPainterPath(outline, true);
                ite->setFillEvenOdd(outline.fillRule() == Qt::OddEvenFill);
        }
        ite->ClipEdited = true;
        ite->FrameType = 3;
        ite->setFillShade(m_currFillShade);
        ite->setLineShade(100);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        ite->setLineEnd(m_lineEnd);
        ite->setLineJoin(m_lineJoin);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        ite->GrType = 8;
        ite->setPattern(id);
        ite->setPatternTransform(fabs(pmat[0]) * 100, fabs(pmat[3]) * 100, mmx.dx() - ctm[4], mmx.dy() - ctm[5], 0, -1 * pmat[1], pmat[2]);
        m_doc->adjustItemSize(ite);
        m_Elements->append(ite);
        if (m_groupStack.count() != 0)
        {
                m_groupStack.top().Items.append(ite);
                applyMask(ite);
        }
        delete gfx;
        return gTrue;
}

void SlaOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool interpolate, GBool inlineImg)
{
//      qDebug() << "Draw Image Mask";
        QImage * image = nullptr;
        int invert_bit;
        int row_stride;
        int x, y, i, bit;
        unsigned char *dest = nullptr;
        unsigned char *buffer;
        Guchar *pix;
        ImageStream * imgStr = new ImageStream(str, width, 1, 1);
        imgStr->reset();
#ifdef WORDS_BIGENDIAN
        image = new QImage(width, height, QImage::Format_Mono);
#else
        image = new QImage(width, height, QImage::Format_MonoLSB);
#endif
        if (image == nullptr || image->isNull())
        {
                delete imgStr;
                delete image;
                return;
        }
        invert_bit = invert ? 1 : 0;
        buffer = image->bits();
        row_stride = image->bytesPerLine();
        for (y = 0; y < height; y++)
        {
                pix = imgStr->getLine();
                dest = buffer + y * row_stride;
                i = 0;
                bit = 0;
                for (x = 0; x < width; x++)
                {
                        if (bit == 0)
                                dest[i] = 0;
                        if (!(pix[x] ^ invert_bit))
                        {
#ifdef WORDS_BIGENDIAN
                                dest[i] |= (1 << (7 - bit));
#else
                                dest[i] |= (1 << bit);
#endif
                        }
                        bit++;
                        if (bit > 7)
                        {
                                bit = 0;
                                i++;
                        }
                }
        }
        QColor backColor = ScColorEngine::getShadeColorProof(m_doc->PageColors[m_currColorFill], m_doc, m_currFillShade);
        QImage res = QImage(width, height, QImage::Format_ARGB32);
        res.fill(backColor.rgb());
        unsigned char cc, cm, cy, ck;
        for (int yi = 0; yi < res.height(); ++yi)
        {
                QRgb *t = (QRgb*)(res.scanLine( yi ));
                for (int xi = 0; xi < res.width(); ++xi)
                {
                        cc = qRed(*t);
                        cm = qGreen(*t);
                        cy = qBlue(*t);
                        ck = image->pixel(xi, yi);
                        if (ck == 0)
                                (*t) = qRgba(cc, cm, cy, 0);
                        else
                                (*t) = qRgba(cc, cm, cy, 255);
                        t++;
                }
        }

        createImageFrame(res, state, 3);

        imgStr->close();
        delete imgStr;
        delete image;
}

void SlaOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, Stream *maskStr, int maskWidth, int maskHeight,
                                   GfxImageColorMap *maskColorMap, GBool maskInterpolate)
{
//      qDebug() << "SlaOutputDev::drawSoftMaskedImage Masked Image Components" << colorMap->getNumPixelComps();
        ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
        imgStr->reset();
        unsigned int *dest = nullptr;
        unsigned char * buffer = new unsigned char[width * height * 4];
        QImage * image = nullptr;
        for (int y = 0; y < height; y++)
        {
                dest = (unsigned int *)(buffer + y * 4 * width);
                Guchar * pix = imgStr->getLine();
                colorMap->getRGBLine(pix, dest, width);
        }
        image = new QImage(buffer, width, height, QImage::Format_RGB32);
        if (image == nullptr || image->isNull())
        {
                delete imgStr;
                delete[] buffer;
                delete image;
                return;
        }
        ImageStream *mskStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits());
        mskStr->reset();
        Guchar *mdest = nullptr;
        unsigned char * mbuffer = new unsigned char[maskWidth * maskHeight];
        memset(mbuffer, 0, maskWidth * maskHeight);
        for (int y = 0; y < maskHeight; y++)
        {
                mdest = (Guchar *)(mbuffer + y * maskWidth);
                Guchar * pix = mskStr->getLine();
                maskColorMap->getGrayLine(pix, mdest, maskWidth);
        }
        if ((maskWidth != width) || (maskHeight != height))
                *image = image->scaled(maskWidth, maskHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        QImage res = image->convertToFormat(QImage::Format_ARGB32);

        int matteRc, matteGc, matteBc;
        POPPLER_CONST_070 GfxColor *matteColor = maskColorMap->getMatteColor();
        if (matteColor != nullptr)
        {
                GfxRGB matteRgb;
                colorMap->getColorSpace()->getRGB(matteColor, &matteRgb);
                matteRc = qRound(colToDbl(matteRgb.r) * 255);
                matteGc = qRound(colToDbl(matteRgb.g) * 255);
                matteBc = qRound(colToDbl(matteRgb.b) * 255);
        }

        unsigned char cr, cg, cb, ca;
        int s = 0;
        for (int yi=0; yi < res.height(); ++yi)
        {
                QRgb *t = (QRgb*)(res.scanLine( yi ));
                for (int xi=0; xi < res.width(); ++xi)
                {
                        cr = qRed(*t);
                        cg = qGreen(*t);
                        cb = qBlue(*t);
                        ca = mbuffer[s];
                        if (matteColor != nullptr)
                        {
                                cr = unblendMatte(cr, ca, matteRc);
                                cg = unblendMatte(cg, ca, matteGc);
                                cb = unblendMatte(cb, ca, matteBc);
                        }
                        (*t) = qRgba(cr, cg, cb, ca);
                        s++;
                        t++;
                }
        }

        createImageFrame(res, state, 3);

        delete imgStr;
        delete[] buffer;
        delete image;
        delete mskStr;
        delete[] mbuffer;
}

void SlaOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,  int width, int height, GfxImageColorMap *colorMap, GBool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert, GBool maskInterpolate)
{
//      qDebug() << "SlaOutputDev::drawMaskedImage";
        ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
        imgStr->reset();
        unsigned int *dest = nullptr;
        unsigned char * buffer = new unsigned char[width * height * 4];
        QImage * image = nullptr;
        for (int y = 0; y < height; y++)
        {
                dest = (unsigned int *)(buffer + y * 4 * width);
                Guchar * pix = imgStr->getLine();
                colorMap->getRGBLine(pix, dest, width);
        }
        image = new QImage(buffer, width, height, QImage::Format_RGB32);
        if (image == nullptr || image->isNull())
        {
                delete imgStr;
                delete[] buffer;
                delete image;
                return;
        }
        ImageStream *mskStr = new ImageStream(maskStr, maskWidth, 1, 1);
        mskStr->reset();
        Guchar *mdest = nullptr;
        int invert_bit = maskInvert ? 1 : 0;
        unsigned char * mbuffer = new unsigned char[maskWidth * maskHeight];
        memset(mbuffer, 0, maskWidth * maskHeight);
        for (int y = 0; y < maskHeight; y++)
        {
                mdest = (Guchar *)(mbuffer + y * maskWidth);
                Guchar * pix = mskStr->getLine();
                for (int x = 0; x < maskWidth; x++)
                {
                        if (pix[x] ^ invert_bit)
                                *mdest++ = 0;
                        else
                                *mdest++ = 255;
                }
        }
        if ((maskWidth != width) || (maskHeight != height))
                *image = image->scaled(maskWidth, maskHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
        QImage res = image->convertToFormat(QImage::Format_ARGB32);
        unsigned char cc, cm, cy, ck;
        int s = 0;
        for (int yi=0; yi < res.height(); ++yi)
        {
                QRgb *t = (QRgb*)(res.scanLine( yi ));
                for (int xi=0; xi < res.width(); ++xi)
                {
                        cc = qRed(*t);
                        cm = qGreen(*t);
                        cy = qBlue(*t);
                        ck = mbuffer[s];
                        (*t) = qRgba(cc, cm, cy, ck);
                        s++;
                        t++;
                }
        }

        createImageFrame(res, state, colorMap->getNumPixelComps());

        delete imgStr;
        delete[] buffer;
        delete image;
        delete mskStr;
        delete[] mbuffer;
}

void SlaOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, GBool interpolate, POPPLER_CONST_082 int* maskColors, GBool inlineImg)
{
        ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits());
//      qDebug() << "SlaOutputDev::drawImage Image Components" << colorMap->getNumPixelComps() << "Mask" << maskColors;
        imgStr->reset();
        QImage* image = nullptr;
        if (maskColors)
        {
                image = new QImage(width, height, QImage::Format_ARGB32);
                for (int y = 0; y < height; y++)
                {
                        QRgb *s = (QRgb*)(image->scanLine(y));
                        Guchar *pix = imgStr->getLine();
                        for (int x = 0; x < width; x++)
                        {
                                GfxRGB rgb;
                                colorMap->getRGB(pix, &rgb);
                                int Rc = qRound(colToDbl(rgb.r) * 255);
                                int Gc = qRound(colToDbl(rgb.g) * 255);
                                int Bc = qRound(colToDbl(rgb.b) * 255);
                                *s = qRgba(Rc, Gc, Bc, 255);
                                for (int i = 0; i < colorMap->getNumPixelComps(); ++i)
                                {
                                        if (pix[i] < maskColors[2*i] * 255 || pix[i] > maskColors[2*i+1] * 255)
                                        {
                                                *s = *s | 0xff000000;
                                                break;
                                        }
                                }
                                s++;
                                pix += colorMap->getNumPixelComps();
                        }
                }
        }
        else
        {
                image = new QImage(width, height, QImage::Format_ARGB32);
                for (int y = 0; y < height; y++)
                {
                        QRgb *s = (QRgb*)(image->scanLine(y));
                        Guchar *pix = imgStr->getLine();
                        for (int x = 0; x < width; x++)
                        {
                                if (colorMap->getNumPixelComps() == 4)
                                {
                                        GfxCMYK cmyk;
                                        colorMap->getCMYK(pix, &cmyk);
                                        int Cc = qRound(colToDbl(cmyk.c) * 255);
                                        int Mc = qRound(colToDbl(cmyk.m) * 255);
                                        int Yc = qRound(colToDbl(cmyk.y) * 255);
                                        int Kc = qRound(colToDbl(cmyk.k) * 255);
                                        *s = qRgba(Yc, Mc, Cc, Kc);
                                }
                                else
                                {
                                        GfxRGB rgb;
                                        colorMap->getRGB(pix, &rgb);
                                        int Rc = qRound(colToDbl(rgb.r) * 255);
                                        int Gc = qRound(colToDbl(rgb.g) * 255);
                                        int Bc = qRound(colToDbl(rgb.b) * 255);
                                        *s = qRgba(Rc, Gc, Bc, 255);
                                }
                                s++;
                                pix += colorMap->getNumPixelComps();
                        }
                }
        }

        if (image != nullptr && !image->isNull()) {
                createImageFrame(*image, state, colorMap->getNumPixelComps());
        }

        delete imgStr;
        delete image;
}

void SlaOutputDev::createImageFrame(QImage& image, GfxState *state, int numColorComponents)
{
//      qDebug() << "SlaOutputDev::createImageFrame";
        const double *ctm = state->getCTM();
        double xCoor = m_doc->currentPage()->xOffset();
        double yCoor = m_doc->currentPage()->yOffset();

        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
        double angle = m_ctm.map(QLineF(0, 0, 1, 0)).angle();
        QPointF torigin;
        // In PDF all images considered squares with unit length that are transformed into the proper
        // dimensions by ctm.
        // A positive determinant retains orientation. Thus orientation is the same as in the PDF
        // coordinate system (y-axis increases upwards). As Scribus uses the inverse orientation the
        // image needs to be flipped (a horizontal flip is applied later).  For a flipped image the
        // corner that will be origin in Scribus is the upper right corner (1, 1) of the image.
        // A negative determinant changes the orientation such that the image is already in the Scribus
        // coordinate orientation and no flip is necessary. The origin will be the upper left corner (0, 1).
        if (m_ctm.determinant() > 0) {
                torigin = m_ctm.map(QPointF(1, 1));
        } else {
                torigin = m_ctm.map(QPointF(0, 1));
        }

        // Determine the visible area of the picture after clipping it. If it is empty, no item
        // needs to be created.
        QPainterPath outline;
        outline.addRect(0, 0, 1, 1);
        outline = m_ctm.map(outline);
        outline = intersection(outline, m_currentClipPath);

        if ((inPattern == 0) && (outline.isEmpty() || outline.boundingRect().isNull()))
                return;

    // Determine the width and height of the image by undoing the rotation part
        // of the CTM and applying the result to the unit square.
        QTransform without_rotation;
        without_rotation = m_ctm * without_rotation.rotate(angle);
        QRectF trect_wr = without_rotation.mapRect(QRectF(0, 0, 1, 1));

        int z = m_doc->itemAdd(PageItem::ImageFrame, PageItem::Rectangle, xCoor + torigin.x(), yCoor + torigin.y(), trect_wr.width(), trect_wr.height(), 0, CommonStrings::None, CommonStrings::None);
        PageItem* ite = m_doc->Items->at(z);
        ite->ClipEdited = true;
        ite->FrameType = 3;
        m_doc->setRedrawBounding(ite);
        ite->Clip = flattenPath(ite->PoLine, ite->Segments);
        ite->setTextFlowMode(PageItem::TextFlowDisabled);
        ite->setFillShade(100);
        ite->setLineShade(100);
        ite->setFillEvenOdd(false);
        ite->setFillTransparency(1.0 - state->getFillOpacity());
        ite->setFillBlendmode(getBlendMode(state));
        if (m_ctm.determinant() > 0)
        {
                ite->setRotation(-(angle - 180));
                ite->setImageFlippedH(true);
        }
        else
                ite->setRotation(-angle);
        m_doc->adjustItemSize(ite);

        if (numColorComponents == 4)
        {
                QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_pdf_XXXXXX.tif");
                tempFile->setAutoRemove(false);
                if (tempFile->open())
                {
                        QString fileName = getLongPathName(tempFile->fileName());
                        if (!fileName.isEmpty())
                        {
                                tempFile->close();
                                ite->isInlineImage = true;
                                ite->isTempFile = true;
                                ite->AspectRatio = false;
                                ite->ScaleType   = false;
                                TIFF* tif = TIFFOpen(fileName.toLocal8Bit().data(), "w");
                                if (tif)
                                {
                                        TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, image.width());
                                        TIFFSetField(tif, TIFFTAG_IMAGELENGTH, image.height());
                                        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
                                        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
                                        TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
                                        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
                                        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
                                        for (int y = 0; y < image.height(); ++y)
                                        {
                                                TIFFWriteScanline(tif, image.scanLine(y), y);
                                        }
                                        TIFFClose(tif);
                                        m_doc->loadPict(fileName, ite);
                                }
                                m_Elements->append(ite);
                                if (m_groupStack.count() != 0)
                                {
                                        m_groupStack.top().Items.append(ite);
                                        applyMask(ite);
                                }
                        }
                        else
                                m_doc->Items->removeAll(ite);
                }
                delete tempFile;
        }
        else
        {
                QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_pdf_XXXXXX.png");
                tempFile->setAutoRemove(false);
                if (tempFile->open())
                {
                        QString fileName = getLongPathName(tempFile->fileName());
                        if (!fileName.isEmpty())
                        {
                                tempFile->close();
                                ite->isInlineImage = true;
                                ite->isTempFile = true;
                                ite->AspectRatio = false;
                                ite->ScaleType   = false;
                                image.save(fileName, "PNG");
                                m_doc->loadPict(fileName, ite);
                                m_Elements->append(ite);
                                if (m_groupStack.count() != 0)
                                {
                                        m_groupStack.top().Items.append(ite);
                                        applyMask(ite);
                                }
                        }
                        else
                                m_doc->Items->removeAll(ite);
                }
                delete tempFile;
        }
        if (inPattern == 0)
        {
                outline.translate(xCoor - ite->xPos(), yCoor - ite->yPos());
                // Undo the rotation of the clipping path as it is rotated together with the image.
                QTransform mm;
                mm.rotate(-ite->rotation());
                outline = mm.map(outline);
                ite->PoLine.fromQPainterPath(outline, true);
                ite->setFillEvenOdd(outline.fillRule() == Qt::OddEvenFill);
                ite->ClipEdited = true;
                ite->FrameType = 3;
                ite->setTextFlowMode(PageItem::TextFlowDisabled);
                ite->ScaleType   = true;
                m_doc->adjustItemSize(ite);
                ite->OldB2 = ite->width();
                ite->OldH2 = ite->height();
                ite->updateClip();
        }
}

void SlaOutputDev::beginMarkedContent(POPPLER_CONST char *name, Object *dictRef)
{
        mContent mSte;
        mSte.name = QString(name);
        mSte.ocgName = "";
        if (importerFlags & LoadSavePlugin::lfCreateDoc)
        {
                if (dictRef->isNull())
                        return;
                Object dictObj;
                Dict *dict;
                Object dictType;
                OCGs *contentConfig = catalog->getOptContentConfig();
                OptionalContentGroup *oc;
                if (dictRef->isRef())
                {
                        oc = contentConfig->findOcgByRef(dictRef->getRef());
                        if (oc)
                        {
//                              qDebug() << "Begin OCG Content (Ref) with Name " << QString(name) << "Layer" << UnicodeParsedString(oc->getName());
                                m_doc->setActiveLayer(UnicodeParsedString(oc->getName()));
                                mSte.ocgName = UnicodeParsedString(oc->getName());
                        }
                }
                else
                {
                        dictObj = dictRef->fetch(xref);
                        if (!dictObj.isDict())
                                return;
                        dict = dictObj.getDict();
                        dictType = dict->lookup("Type");
                        if (dictType.isName("OCG"))
                        {
                                oc = contentConfig->findOcgByRef(dictRef->getRef());
                                if (oc)
                                {
                                        //                                      qDebug() << "Begin OCG Content with Name " << UnicodeParsedString(oc->getName());
                                        m_doc->setActiveLayer(UnicodeParsedString(oc->getName()));
                                        mSte.ocgName = UnicodeParsedString(oc->getName());
                                }
                        }
                }
        }
        m_mcStack.push(mSte);
}

void SlaOutputDev::beginMarkedContent(POPPLER_CONST char *name, Dict *properties)
{
//      qDebug() << "Begin Marked Content with Name " << QString(name);
        QString nam = QString(name);
        mContent mSte;
        mSte.name = nam;
        mSte.ocgName = "";
        m_mcStack.push(mSte);
        if (importerFlags & LoadSavePlugin::lfCreateDoc)
        {
                if (nam == "Layer")             // Handle Adobe Illustrator Layer command
                {
                        if (layersSetByOCG)
                                return;
                        QString lName = QString("Layer_%1").arg(layerNum + 1);
                        Object obj = properties->lookup((char*) "Title");
                        if (obj.isString())
                                lName = QString(obj.getString()->getCString());
                        for (ScLayers::iterator it = m_doc->Layers.begin(); it != m_doc->Layers.end(); ++it)
                        {
                                if (it->Name == lName)
                                {
                                        m_doc->setActiveLayer(lName);
                                        return;
                                }
                        }
                        layerNum++;
                        if (!firstLayer)
                                currentLayer = m_doc->addLayer(lName, true);
                        firstLayer = false;

                        obj = properties->lookup((char*) "Visible");
                        if (obj.isBool())
                                m_doc->setLayerVisible(currentLayer, obj.getBool());
                        obj = properties->lookup((char*) "Editable");
                        if (obj.isBool())
                                m_doc->setLayerLocked(currentLayer, !obj.getBool());
                        obj = properties->lookup((char*) "Printed");
                        if (obj.isBool())
                                m_doc->setLayerPrintable(currentLayer, obj.getBool());
                        obj = properties->lookup((char*)"Color");
                        if (obj.isArray())
                        {
                                Object obj1;
                                obj1 = obj.arrayGet(0);
                                int r = obj1.getNum() / 256;
                                obj1 = obj.arrayGet(1);
                                int g = obj1.getNum() / 256;
                                obj1 = obj.arrayGet(2);
                                int b = obj1.getNum() / 256;
                                m_doc->setLayerMarker(currentLayer, QColor(r, g, b));
                        }
                }
        }
}

void SlaOutputDev::endMarkedContent(GfxState *state)
{
//      qDebug() << "End Marked Content";
        if (m_mcStack.count() > 0)
        {
                mContent mSte = m_mcStack.pop();
                if (importerFlags & LoadSavePlugin::lfCreateDoc)
                {
                        if (mSte.name == "OC")
                        {
                                for (ScLayers::iterator it = m_doc->Layers.begin(); it != m_doc->Layers.end(); ++it)
                                {
                                        if (it->Name == mSte.ocgName)
                                        {
                                                m_doc->setActiveLayer(mSte.ocgName);
                                                return;
                                        }
                                }
                        }
                }
        }
}

void SlaOutputDev::markPoint(POPPLER_CONST char *name)
{
//      qDebug() << "Begin Marked Point with Name " << QString(name);
}

void SlaOutputDev::markPoint(POPPLER_CONST char *name, Dict *properties)
{
//      qDebug() << "Begin Marked Point with Name " << QString(name) << "and Properties";
        beginMarkedContent(name, properties);
}

void SlaOutputDev::updateFont(GfxState *state)
{
        GfxFont *gfxFont;
        GfxFontLoc *fontLoc;
        GfxFontType fontType;
        SlaOutFontFileID *id;
        SplashFontFile *fontFile;
        SplashFontSrc *fontsrc = nullptr;
        FoFiTrueType *ff;
        Object refObj, strObj;
        GooString *fileName;
        char *tmpBuf;
        int tmpBufLen = 0;
        int *codeToGID;
        const double *textMat;
        double m11, m12, m21, m22, fontSize;
        SplashCoord mat[4];
        int n = 0;
        int faceIndex = 0;
        SplashCoord matrix[6];

        m_font = nullptr;
        fileName = nullptr;
        tmpBuf = nullptr;
        fontLoc = nullptr;

        gfxFont = state->getFont();
        if (!gfxFont)
                goto err1;

        fontType = gfxFont->getType();
        if (fontType == fontType3)
                goto err1;

        // check the font file cache
        id = new SlaOutFontFileID(gfxFont->getID());
        if ((fontFile = m_fontEngine->getFontFile(id)))
                delete id;
        else
        {
                if (!(fontLoc = gfxFont->locateFont(xref, nullptr)))
                {
                        error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
                        gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                        goto err2;
                }

                // embedded font
                if (fontLoc->locType == gfxFontLocEmbedded)
                {
                        // if there is an embedded font, read it to memory
                        tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
                        if (! tmpBuf)
                                goto err2;

                        // external font
                }
                else
                { // gfxFontLocExternal
                        fileName = fontLoc->path;
                        fontType = fontLoc->fontType;
                }

                fontsrc = new SplashFontSrc;
                if (fileName)
                        fontsrc->setFile(fileName, gFalse);
                else
                        fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);

                // load the font file
                switch (fontType) {
                case fontType1:
                        if (!(fontFile = m_fontEngine->loadType1Font(
                                id,
                                fontsrc,
                                (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontType1C:
                        if (!(fontFile = m_fontEngine->loadType1CFont(
                                                        id,
                                                        fontsrc,
                                                        (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontType1COT:
                        if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont(
                                                        id,
                                                        fontsrc,
                                                        (const char **)((Gfx8BitFont *) gfxFont)->getEncoding())))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontTrueType:
                case fontTrueTypeOT:
                        if (fileName)
                                ff = FoFiTrueType::load(fileName->getCString());
                        else
                                ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
                        if (ff)
                        {
                                codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
                                n = 256;
                                delete ff;
                        }
                        else
                        {
                                codeToGID = nullptr;
                                n = 0;
                        }
                        if (!(fontFile = m_fontEngine->loadTrueTypeFont(
                                                        id,
                                                        fontsrc,
                                                        codeToGID, n)))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontCIDType0:
                case fontCIDType0C:
                        if (!(fontFile = m_fontEngine->loadCIDFont(
                                                        id,
                                                        fontsrc)))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontCIDType0COT:
                        if (((GfxCIDFont *) gfxFont)->getCIDToGID())
                        {
                                n = ((GfxCIDFont *) gfxFont)->getCIDToGIDLen();
                                codeToGID = (int *) gmallocn(n, sizeof(*codeToGID));
                                memcpy(codeToGID, ((GfxCIDFont *) gfxFont)->getCIDToGID(), n * sizeof(*codeToGID));
                        }
                        else
                        {
                                codeToGID = nullptr;
                                n = 0;
                        }
                        if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont(
                                                        id,
                                                        fontsrc,
                                                        codeToGID, n)))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                case fontCIDType2:
                case fontCIDType2OT:
                        codeToGID = nullptr;
                        n = 0;
                        if (((GfxCIDFont *) gfxFont)->getCIDToGID())
                        {
                                n = ((GfxCIDFont *) gfxFont)->getCIDToGIDLen();
                                if (n)
                                {
                                        codeToGID = (int *)gmallocn(n, sizeof(*codeToGID));
                                        memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(*codeToGID));
                                }
                        }
                        else
                        {
                                if (fileName)
                                        ff = FoFiTrueType::load(fileName->getCString());
                                else
                                        ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
                                if (! ff)
                                        goto err2;
                                codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
                                delete ff;
                        }
                        if (!(fontFile = m_fontEngine->loadTrueTypeFont(
                                                        id,
                                                        fontsrc,
                                                        codeToGID, n, faceIndex)))
                        {
                                error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'",
                                gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)");
                                goto err2;
                        }
                        break;
                default:
                        // this shouldn't happen
                        goto err2;
                }
        }
        // get the font matrix
        textMat = state->getTextMat();
        fontSize = state->getFontSize();
        m11 = textMat[0] * fontSize * state->getHorizScaling();
        m12 = textMat[1] * fontSize * state->getHorizScaling();
        m21 = textMat[2] * fontSize;
        m22 = textMat[3] * fontSize;
        matrix[0] = 1;
        matrix[1] = 0;
        matrix[2] = 0;
        matrix[3] = 1;
        matrix[4] = 0;
        matrix[5] = 0;
        // create the scaled font
        mat[0] = m11;
        mat[1] = -m12;
        mat[2] = m21;
        mat[3] = -m22;
        m_font = m_fontEngine->getFont(fontFile, mat, matrix);

        delete fontLoc;
        if (fontsrc && !fontsrc->isFile)
                fontsrc->unref();
        return;

err2:
        delete id;
        delete fontLoc;
err1:
        if (fontsrc && !fontsrc->isFile)
                fontsrc->unref();
}

void SlaOutputDev::drawChar(GfxState* state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, POPPLER_CONST_082 Unicode* u, int uLen)
{
//      qDebug() << "SlaOutputDev::drawChar code:" << code << "bytes:" << nBytes << "Unicode:" << u << "ulen:" << uLen << "render:" << state->getRender();
        double x1, y1, x2, y2;
        updateFont(state);
        if (!m_font)
                return;

        // PDF 1.7 Section 9.3.6 defines eight text rendering modes.
        // 0 - Fill
        // 1 - Stroke
        // 2 - First fill and then stroke
        // 3 - Invisible
        // 4 - Fill and use as a clipping path
        // 5 - Stroke and use as a clipping path
        // 6 - First fill, then stroke and add as a clipping path
        // 7 - Only use as a clipping path.
        // TODO Implement the clipping operations. At least the characters are shown.
        int textRenderingMode = state->getRender();
        // Invisible or only used for clipping
        if (textRenderingMode == 3)
                return;
        if (textRenderingMode < 8)
        {
                SplashPath * fontPath;
                fontPath = m_font->getGlyphPath(code);
                if (fontPath)
                {
                        QPainterPath qPath;
                        qPath.setFillRule(Qt::WindingFill);
                        for (int i = 0; i < fontPath->getLength(); ++i)
                        {
                                Guchar f;
                                fontPath->getPoint(i, &x1, &y1, &f);
                                if (f & splashPathFirst)
                                        qPath.moveTo(x1,y1);
                                else if (f & splashPathCurve)
                                {
                                        double x3, y3;
                                        ++i;
                                        fontPath->getPoint(i, &x2, &y2, &f);
                                        ++i;
                                        fontPath->getPoint(i, &x3, &y3, &f);
                                        qPath.cubicTo(x1,y1,x2,y2,x3,y3);
                                }
                                else
                                        qPath.lineTo(x1, y1);
                                if (f & splashPathLast)
                                        qPath.closeSubpath();
                        }
                        const double * ctm = state->getCTM();
                        m_ctm = QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]);
                        double xCoor = m_doc->currentPage()->xOffset();
                        double yCoor = m_doc->currentPage()->yOffset();
                        FPointArray textPath;
                        textPath.fromQPainterPath(qPath);
                        FPoint wh = textPath.widthHeight();
                        if (textRenderingMode > 3)
                        {
                                QTransform mm;
                                mm.scale(1, -1);
                                mm.translate(x, -y);
                                // Remember the glyph for later clipping
                                m_clipTextPath.addPath(m_ctm.map(mm.map(qPath)));
                        }
                        if ((textPath.size() > 3) && ((wh.x() != 0.0) || (wh.y() != 0.0)) && (textRenderingMode != 7))
                        {
                                int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, xCoor, yCoor, 10, 10, 0, CommonStrings::None, CommonStrings::None);
                                PageItem* ite = m_doc->Items->at(z);

                                // todo: merge this between vector and text implementations.
                                QTransform mm;
                                mm.scale(1, -1);
                                mm.translate(x, -y);
                                textPath.map(mm);
                                textPath.map(m_ctm);
                                ite->PoLine = textPath.copy();
                                setItemFillAndStroke(state, ite);
                                // Fill text rendering modes. See above
                                m_doc->adjustItemSize(ite);
                                m_Elements->append(ite);
                                if (m_groupStack.count() != 0)
                                {
                                        m_groupStack.top().Items.append(ite);
                                        applyMask(ite);
                                }
                        }
                        delete fontPath;

                }
        }
}


GBool SlaOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, POPPLER_CONST_082 Unicode *u, int uLen)
{
//      qDebug() << "beginType3Char";
        GfxFont *gfxFont;
        if (!(gfxFont = state->getFont()))
                return gTrue;
        if (gfxFont->getType() != fontType3)
                return gTrue;
        F3Entry f3e;
        f3e.colored = false;
        m_F3Stack.push(f3e);
        pushGroup();
        return gFalse;
}

void SlaOutputDev::endType3Char(GfxState *state)
{
//      qDebug() << "endType3Char";
        F3Entry f3e = m_F3Stack.pop();
        groupEntry gElements = m_groupStack.pop();
        m_doc->m_Selection->clear();
        if (gElements.Items.count() > 0)
        {
                m_doc->m_Selection->delaySignalsOn();
                for (int dre = 0; dre < gElements.Items.count(); ++dre)
                {
                        m_doc->m_Selection->addItem(gElements.Items.at(dre), true);
                        m_Elements->removeAll(gElements.Items.at(dre));
                }
                PageItem *ite;
                if (m_doc->m_Selection->count() > 1)
                        ite = m_doc->groupObjectsSelection();
                else
                        ite = m_doc->m_Selection->itemAt(0);
                if (!f3e.colored)
                {
                        m_doc->itemSelection_SetItemBrush(m_currColorFill);
                        m_doc->itemSelection_SetItemBrushShade(m_currFillShade);
                        m_doc->itemSelection_SetItemFillTransparency(1.0 - state->getFillOpacity());
                        m_doc->itemSelection_SetItemFillBlend(getBlendMode(state));
                }
                m_Elements->append(ite);
                m_doc->m_Selection->clear();
                m_doc->m_Selection->delaySignalsOff();
        }
}

void SlaOutputDev::type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/)
{
//      qDebug() << "type3D0";
        if (m_F3Stack.count() > 0)
                m_F3Stack.top().colored = true;
}

void SlaOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury)
{
//      qDebug() << "type3D1";
        if (m_F3Stack.count() > 0)
                m_F3Stack.top().colored = false;
}

void SlaOutputDev::beginTextObject(GfxState *state)
{
        pushGroup();
}

void SlaOutputDev::endTextObject(GfxState *state)
{
//      qDebug() << "SlaOutputDev::endTextObject";
        if (!m_clipTextPath.isEmpty())
        {
                m_currentClipPath = intersection(m_currentClipPath, m_clipTextPath);
                m_clipTextPath = QPainterPath();
        }
        if (m_groupStack.count() != 0)
        {
                groupEntry gElements = m_groupStack.pop();
                tmpSel->clear();
                if (gElements.Items.count() > 0)
                {
                        for (int dre = 0; dre < gElements.Items.count(); ++dre)
                        {
                                tmpSel->addItem(gElements.Items.at(dre), true);
                                m_Elements->removeAll(gElements.Items.at(dre));
                        }
                        PageItem *ite;
                        if (gElements.Items.count() != 1)
                                ite = m_doc->groupObjectsSelection(tmpSel);
                        else
                                ite = gElements.Items.first();
                        ite->setGroupClipping(false);
                        ite->setFillTransparency(1.0 - state->getFillOpacity());
                        ite->setFillBlendmode(getBlendMode(state));
                        for (int as = 0; as < tmpSel->count(); ++as)
                        {
                                m_Elements->append(tmpSel->itemAt(as));
                        }
                        if (m_groupStack.count() != 0)
                                applyMask(ite);
                }
                if (m_groupStack.count() != 0)
                {
                        for (int as = 0; as < tmpSel->count(); ++as)
                        {
                                m_groupStack.top().Items.append(tmpSel->itemAt(as));
                        }
                }
                tmpSel->clear();
        }
}

QString SlaOutputDev::getColor(GfxColorSpace *color_space, POPPLER_CONST_070 GfxColor *color, int *shade)
{
        QString fNam;
        QString namPrefix = "FromPDF";
        ScColor tmp;
        tmp.setSpotColor(false);
        tmp.setRegistrationColor(false);
        *shade = 100;
        /*if (m_F3Stack.count() > 0)
        {
                if (!m_F3Stack.top().colored)
                        return "Black";
        }*/


        if ((color_space->getMode() == csDeviceRGB) || (color_space->getMode() == csCalRGB))
        {
                GfxRGB rgb;
                color_space->getRGB(color, &rgb);
                double Rc = colToDbl(rgb.r);
                double Gc = colToDbl(rgb.g);
                double Bc = colToDbl(rgb.b);
                tmp.setRgbColorF(Rc, Gc, Bc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if (color_space->getMode() == csDeviceCMYK)
        {
                GfxCMYK cmyk;
                color_space->getCMYK(color, &cmyk);
                double Cc = colToDbl(cmyk.c);
                double Mc = colToDbl(cmyk.m);
                double Yc = colToDbl(cmyk.y);
                double Kc = colToDbl(cmyk.k);
                tmp.setCmykColorF(Cc, Mc, Yc, Kc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if ((color_space->getMode() == csCalGray) || (color_space->getMode() == csDeviceGray))
        {
                GfxGray gray;
                color_space->getGray(color, &gray);
                double Kc = 1.0 - colToDbl(gray);
                tmp.setCmykColorF(0, 0, 0, Kc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
        }
        else if (color_space->getMode() == csSeparation)
        {
                GfxSeparationColorSpace* sepColorSpace = (GfxSeparationColorSpace*) color_space;
                GfxColorSpace* altColorSpace = sepColorSpace->getAlt();
                QString name = QString(sepColorSpace->getName()->getCString());
                bool isRegistrationColor = (name == "All");
                if (isRegistrationColor)
                {
                        tmp.setCmykColorF(1.0, 1.0, 1.0, 1.0);
                        tmp.setRegistrationColor(true);
                        name = "Registration";
                }
                else if ((altColorSpace->getMode() == csDeviceRGB) || (altColorSpace->getMode() == csCalRGB))
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setRgbColorF(comps[0], comps[1], comps[2]);
                }
                else if ((altColorSpace->getMode() == csCalGray) || (altColorSpace->getMode() == csDeviceGray))
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setCmykColorF(0.0, 0.0, 0.0, 1.0 - comps[0]);
                }
                else if (altColorSpace->getMode() == csLab)
                {
                        double x = 1.0;
                        double comps[gfxColorMaxComps];
                        sepColorSpace->getFunc()->transform(&x, comps);
                        tmp.setLabColor(comps[0], comps[1], comps[2]);
                }
                else
                {
                        GfxCMYK cmyk;
                        color_space->getCMYK(color, &cmyk);
                        double Cc = colToDbl(cmyk.c);
                        double Mc = colToDbl(cmyk.m);
                        double Yc = colToDbl(cmyk.y);
                        double Kc = colToDbl(cmyk.k);
                        tmp.setCmykColorF(Cc, Mc, Yc, Kc);
                }
                tmp.setSpotColor(true);

                fNam = m_doc->PageColors.tryAddColor(name, tmp);
                *shade = qRound(colToDbl(color->c[0]) * 100);
        }
        else
        {
                GfxRGB rgb;
                color_space->getRGB(color, &rgb);
                double Rc = colToDbl(rgb.r);
                double Gc = colToDbl(rgb.g);
                double Bc = colToDbl(rgb.b);
                tmp.setRgbColorF(Rc, Gc, Bc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp);
//              qDebug() << "update fill color other colorspace" << color_space->getMode() << "treating as rgb" << Rc << Gc << Bc;
        }
        if (fNam == namPrefix+tmp.name())
                m_importedColors->append(fNam);
        return fNam;
}

QString SlaOutputDev::getAnnotationColor(const AnnotColor *color)
{
        QString fNam;
        QString namPrefix = "FromPDF";
        ScColor tmp;
        tmp.setSpotColor(false);
        tmp.setRegistrationColor(false);
        if (color->getSpace() == AnnotColor::colorTransparent)
                return CommonStrings::None;
        if (color->getSpace() == AnnotColor::colorRGB)
        {
                const double *color_data = color->getValues();
                double Rc = color_data[0];
                double Gc = color_data[1];
                double Bc = color_data[2];
                tmp.setRgbColorF(Rc, Gc, Bc);
                fNam = m_doc->PageColors.tryAddColor(namPrefix+tmp.name(), tmp)</