/* poppler-ps-converter.cc: qt interface to poppler * Copyright (C) 2007, 2009, 2010, 2015, 2020, 2022, Albert Astals Cid * Copyright (C) 2008, Pino Toscano * Copyright (C) 2010 Hib Eris * Copyright (C) 2011 Glad Deschrijver * Copyright (C) 2012 Fabio D'Urso * Copyright (C) 2013 Thomas Freitag * Copyright (C) 2014 Adrian Johnson * Copyright (C) 2020 William Bader * Copyright (C) 2023 Kevin Ottens . Work sponsored by De Bortoli Wines * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "poppler-qt6.h" #include "poppler-private.h" #include "poppler-converter-private.h" #include "PSOutputDev.h" static void outputToQIODevice(void *stream, const char *data, size_t len) { static_cast(stream)->write(data, len); } namespace Poppler { class PSConverterPrivate : public BaseConverterPrivate { public: PSConverterPrivate(); ~PSConverterPrivate() override; QList pageList; QString title; double hDPI; double vDPI; int rotate; int paperWidth; int paperHeight; int marginRight; int marginBottom; int marginLeft; int marginTop; PSConverter::PSOptions opts; void (*pageConvertedCallback)(int page, void *payload); void *pageConvertedPayload; }; PSConverterPrivate::PSConverterPrivate() : BaseConverterPrivate(), hDPI(72), vDPI(72), rotate(0), paperWidth(-1), paperHeight(-1), marginRight(0), marginBottom(0), marginLeft(0), marginTop(0), opts(PSConverter::Printing), pageConvertedCallback(nullptr), pageConvertedPayload(nullptr) { } PSConverterPrivate::~PSConverterPrivate() = default; PSConverter::PSConverter(DocumentData *document) : BaseConverter(*new PSConverterPrivate()) { Q_D(PSConverter); d->document = document; } PSConverter::~PSConverter() { } void PSConverter::setPageList(const QList &pageList) { Q_D(PSConverter); d->pageList = pageList; } void PSConverter::setTitle(const QString &title) { Q_D(PSConverter); d->title = title; } void PSConverter::setHDPI(double hDPI) { Q_D(PSConverter); d->hDPI = hDPI; } void PSConverter::setVDPI(double vDPI) { Q_D(PSConverter); d->vDPI = vDPI; } void PSConverter::setRotate(int rotate) { Q_D(PSConverter); d->rotate = rotate; } void PSConverter::setPaperWidth(int paperWidth) { Q_D(PSConverter); d->paperWidth = paperWidth; } void PSConverter::setPaperHeight(int paperHeight) { Q_D(PSConverter); d->paperHeight = paperHeight; } void PSConverter::setRightMargin(int marginRight) { Q_D(PSConverter); d->marginRight = marginRight; } void PSConverter::setBottomMargin(int marginBottom) { Q_D(PSConverter); d->marginBottom = marginBottom; } void PSConverter::setLeftMargin(int marginLeft) { Q_D(PSConverter); d->marginLeft = marginLeft; } void PSConverter::setTopMargin(int marginTop) { Q_D(PSConverter); d->marginTop = marginTop; } void PSConverter::setStrictMargins(bool strictMargins) { Q_D(PSConverter); if (strictMargins) { d->opts |= StrictMargins; } else { d->opts &= ~StrictMargins; } } void PSConverter::setForceOverprintPreview(bool forceOverprintPreview) { Q_D(PSConverter); if (forceOverprintPreview) { d->opts |= ForceOverprintPreview; } else { d->opts &= ~ForceOverprintPreview; } } void PSConverter::setForceRasterize(bool forceRasterize) { Q_D(PSConverter); if (forceRasterize) { d->opts |= ForceRasterization; } else { d->opts &= ~ForceRasterization; } } void PSConverter::setPSOptions(PSConverter::PSOptions options) { Q_D(PSConverter); d->opts = options; } PSConverter::PSOptions PSConverter::psOptions() const { Q_D(const PSConverter); return d->opts; } void PSConverter::setPageConvertedCallback(void (*callback)(int page, void *payload), void *payload) { Q_D(PSConverter); d->pageConvertedCallback = callback; d->pageConvertedPayload = payload; } static bool annotDisplayDecideCbk(Annot *annot, void *user_data) { if (annot->getType() == Annot::typeWidget) { return true; // Never hide forms } else { return *(bool *)user_data; } } bool PSConverter::convert() { Q_D(PSConverter); d->lastError = NoError; Q_ASSERT(!d->pageList.isEmpty()); Q_ASSERT(d->paperWidth != -1); Q_ASSERT(d->paperHeight != -1); if (d->document->locked) { d->lastError = FileLockedError; return false; } QIODevice *dev = d->openDevice(); if (!dev) { d->lastError = OpenOutputError; return false; } QByteArray pstitle8Bit = d->title.toLocal8Bit(); char *pstitlechar; if (!d->title.isEmpty()) { pstitlechar = pstitle8Bit.data(); } else { pstitlechar = nullptr; } std::vector pages; foreach (int page, d->pageList) { pages.push_back(page); } PSOutputDev *psOut = new PSOutputDev(outputToQIODevice, dev, pstitlechar, d->document->doc, pages, (d->opts & PrintToEPS) ? psModeEPS : psModePS, d->paperWidth, d->paperHeight, false, false, d->marginLeft, d->marginBottom, d->paperWidth - d->marginRight, d->paperHeight - d->marginTop, (d->opts & ForceRasterization) ? psAlwaysRasterize : psRasterizeWhenNeeded); if (d->opts & ForceOverprintPreview) { psOut->setForceRasterize(psAlwaysRasterize); psOut->setOverprintPreview(true); } if (d->opts & StrictMargins) { double xScale = ((double)d->paperWidth - (double)d->marginLeft - (double)d->marginRight) / (double)d->paperWidth; double yScale = ((double)d->paperHeight - (double)d->marginBottom - (double)d->marginTop) / (double)d->paperHeight; psOut->setScale(xScale, yScale); } if (psOut->isOk()) { bool isPrinting = (d->opts & Printing) ? true : false; bool showAnnotations = (d->opts & HideAnnotations) ? false : true; foreach (int page, d->pageList) { d->document->doc->displayPage(psOut, page, d->hDPI, d->vDPI, d->rotate, false, true, isPrinting, nullptr, nullptr, annotDisplayDecideCbk, &showAnnotations, true); if (d->pageConvertedCallback) { (*d->pageConvertedCallback)(page, d->pageConvertedPayload); } } delete psOut; d->closeDevice(); return true; } else { delete psOut; d->closeDevice(); return false; } } }