diff --git a/filters/karbon/pdf/SvgOutputDev.cpp b/filters/karbon/pdf/SvgOutputDev.cpp index 1d07f16dc28..870a940f0ee 100644 --- a/filters/karbon/pdf/SvgOutputDev.cpp +++ b/filters/karbon/pdf/SvgOutputDev.cpp @@ -1,549 +1,549 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SvgOutputDev.h" #include "PdfImportDebug.h" #include #include #include #include #include #include #include #include #include #include #include #include class SvgOutputDev::Private { public: Private(const QString &fname) : svgFile(fname), defs(0), body(0), state(gTrue) , brush(Qt::SolidPattern) {} ~Private() { delete defs; delete body; } QFile svgFile; QString bodyData; QString defsData; QTextStream * defs; QTextStream * body; - GBool state; + bool state; QSizeF pageSize; QPen pen; QBrush brush; }; SvgOutputDev::SvgOutputDev(const QString &fileName) : d(new Private(fileName)) { if (! d->svgFile.open(QIODevice::WriteOnly)) { d->state = gFalse; return; } d->body = new QTextStream(&d->bodyData, QIODevice::ReadWrite); d->defs = new QTextStream(&d->defsData, QIODevice::ReadWrite); } SvgOutputDev::~SvgOutputDev() { delete d; } -GBool SvgOutputDev::isOk() +bool SvgOutputDev::isOk() { return d->state; } -GBool SvgOutputDev::upsideDown() +bool SvgOutputDev::upsideDown() { return gTrue; } -GBool SvgOutputDev::useDrawChar() +bool SvgOutputDev::useDrawChar() { return gFalse; } -GBool SvgOutputDev::interpretType3Chars() +bool SvgOutputDev::interpretType3Chars() { return gFalse; } void SvgOutputDev::startPage(int pageNum, GfxState *state, XRef */*xref*/) { debugPdf << "starting page" << pageNum; d->pageSize = QSizeF(state->getPageWidth(), state->getPageHeight()); debugPdf << "page size =" << d->pageSize; *d->body << "body << " display=\"none\""; *d->body << ">" << endl; } void SvgOutputDev::endPage() { debugPdf << "ending page"; *d->body << "" << endl; } void SvgOutputDev::dumpContent() { debugPdf << "dumping pages"; QTextStream stream(&d->svgFile); stream << "" << endl; stream << "" << endl; // add some PR. one line is more than enough. stream << "" << endl; stream << "pageSize.width() << "px\" height=\"" << d->pageSize.height() << "px\">" << endl; stream << "" << endl; stream << d->defsData; stream << "" << endl; stream << d->bodyData; stream << "" << endl; d->svgFile.close(); } void SvgOutputDev::stroke(GfxState * state) { QString path = convertPath(state->getPath()); *d->body << "body << " transform=\"" << convertMatrix(state->getCTM()) << "\""; *d->body << printStroke(); *d->body << " fill=\"none\""; *d->body << " d=\"" << path << "\""; *d->body << "/>" << endl; } void SvgOutputDev::fill(GfxState * state) { QString path = convertPath(state->getPath()); *d->body << "body << " transform=\"" << convertMatrix(state->getCTM()) << "\""; *d->body << printFill(); *d->body << " fill-rule=\"nonzero\""; *d->body << " d=\"" << path << "\""; *d->body << "/>" << endl; } void SvgOutputDev::eoFill(GfxState *state) { QString path = convertPath(state->getPath()); *d->body << "body << " transform=\"" << convertMatrix(state->getCTM()) << "\""; *d->body << printFill(); *d->body << " fill-rule=\"evenodd\""; *d->body << " d=\"" << path << "\""; *d->body << "/>" << endl; } QString SvgOutputDev::convertPath(GfxPath *path) { if (! path) return QString(); QString output; for (int i = 0; i < path->getNumSubpaths(); ++i) { GfxSubpath * subpath = path->getSubpath(i); if (subpath->getNumPoints() > 0) { output += QString("M%1 %2").arg(subpath->getX(0)).arg(subpath->getY(0)); int j = 1; while (j < subpath->getNumPoints()) { if (subpath->getCurve(j)) { output += QString("C%1 %2 %3 %4 %5 %6") .arg(subpath->getX(j)).arg(subpath->getY(j)) .arg(subpath->getX(j + 1)).arg(subpath->getY(j + 1)) .arg(subpath->getX(j + 2)).arg(subpath->getY(j + 2)); j += 3; } else { output += QString("L%1 %2").arg(subpath->getX(j)).arg(subpath->getY(j)); ++j; } } if (subpath->isClosed()) { output += QString("Z"); } } } return output; } QString SvgOutputDev::convertMatrix(const QMatrix &matrix) { return QString("matrix(%1 %2 %3 %4 %5 %6)") .arg(matrix.m11()).arg(matrix.m12()) .arg(matrix.m21()).arg(matrix.m22()) .arg(matrix.dx()) .arg(matrix.dy()); } QString SvgOutputDev::convertMatrix(const double * matrix) { return QString("matrix(%1 %2 %3 %4 %5 %6)") .arg(matrix[0]).arg(matrix[1]) .arg(matrix[2]).arg(matrix[3]) .arg(matrix[4]) .arg(matrix[5]); } void SvgOutputDev::updateAll(GfxState *state) { debugPdf << "update complete state"; //updateLineDash(state); updateLineJoin(state); updateLineCap(state); updateLineWidth(state); //updateFlatness(state); updateMiterLimit(state); updateFillColor(state); updateStrokeColor(state); updateFillOpacity(state); updateStrokeOpacity(state); } void SvgOutputDev::updateFillColor(GfxState *state) { GfxRGB rgb; state->getFillRGB(&rgb); QColor brushColour = d->brush.color(); brushColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), brushColour.alphaF()); d->brush.setColor(brushColour); debugPdf << "update fill color" << brushColour; } void SvgOutputDev::updateStrokeColor(GfxState *state) { GfxRGB rgb; state->getStrokeRGB(&rgb); QColor penColour = d->pen.color(); penColour.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), penColour.alphaF()); d->pen.setColor(penColour); debugPdf << "update stroke color" << penColour; } void SvgOutputDev::updateFillOpacity(GfxState *state) { QColor brushColour = d->brush.color(); brushColour.setAlphaF(state->getFillOpacity()); d->brush.setColor(brushColour); debugPdf << "update fill opacity" << state->getFillOpacity(); } void SvgOutputDev::updateStrokeOpacity(GfxState *state) { QColor penColour = d->pen.color(); penColour.setAlphaF(state->getStrokeOpacity()); d->pen.setColor(penColour); debugPdf << "update stroke opacity" << state->getStrokeOpacity(); } void SvgOutputDev::updateLineJoin(GfxState *state) { switch (state->getLineJoin()) { case 0: d->pen.setJoinStyle(Qt::MiterJoin); break; case 1: d->pen.setJoinStyle(Qt::RoundJoin); break; case 2: d->pen.setJoinStyle(Qt::BevelJoin); break; } } void SvgOutputDev::updateLineCap(GfxState *state) { switch (state->getLineCap()) { case 0: d->pen.setCapStyle(Qt::FlatCap); break; case 1: d->pen.setCapStyle(Qt::RoundCap); break; case 2: d->pen.setCapStyle(Qt::SquareCap); break; } } void SvgOutputDev::updateMiterLimit(GfxState *state) { d->pen.setMiterLimit(state->getMiterLimit()); } void SvgOutputDev::updateLineWidth(GfxState *state) { //d->pen.setWidthF( state->getTransformedLineWidth() ); d->pen.setWidthF(state->getLineWidth()); } QString SvgOutputDev::printFill() { QString fill; fill += " fill=\""; switch (d->brush.style()) { case Qt::NoBrush: fill += "none"; break; case Qt::SolidPattern: fill += d->brush.color().name(); break; default: debugPdf << "unhandled fill style (" << d->brush.style() << ")"; return QString(); break; } fill += "\""; if (d->brush.color().alphaF() < 1.0) fill += QString(" fill-opacity=\"%1\"").arg(d->brush.color().alphaF()); return fill; } QString SvgOutputDev::printStroke() { QString stroke; stroke += " stroke=\""; if (d->pen.style() == Qt::NoPen) stroke += "none"; else stroke += d->pen.color().name(); stroke += "\""; if (d->pen.color().alphaF() < 1.0) stroke += QString(" stroke-opacity=\"%1\"").arg(d->pen.color().alphaF()); stroke += QString(" stroke-width=\"%1\"").arg(d->pen.widthF()); if (d->pen.capStyle() == Qt::FlatCap) stroke += " stroke-linecap=\"butt\""; else if (d->pen.capStyle() == Qt::RoundCap) stroke += " stroke-linecap=\"round\""; else if (d->pen.capStyle() == Qt::SquareCap) stroke += " stroke-linecap=\"square\""; if (d->pen.joinStyle() == Qt::MiterJoin) { stroke += " stroke-linejoin=\"miter\""; stroke += QString(" stroke-miterlimit=\"%1\"").arg(d->pen.miterLimit()); } else if (d->pen.joinStyle() == Qt::RoundJoin) stroke += " stroke-linejoin=\"round\""; else if (d->pen.joinStyle() == Qt::BevelJoin) stroke += " stroke-linejoin=\"bevel\""; // dash if (d->pen.style() > Qt::SolidLine) { //*stream << " stroke-dashoffset=\"" << line->dashPattern().offset() << "\""; stroke += " stroke-dasharray=\" "; foreach(qreal dash, d->pen.dashPattern()) { stroke += dash + ' '; } stroke += "\""; } return stroke; } void SvgOutputDev::drawString(GfxState * state, const GooString * s) { int render = state->getRender(); // check for invisible text -- this is used by Acrobat Capture if (render == 3) return; // ignore empty strings if (s->getLength() == 0) return; GfxFont * font = state->getFont(); QString str; #ifdef HAVE_POPPLER_PRE_0_64 char * p = s->getCString(); #else const char * p = s->getCString(); #endif int len = s->getLength(); CharCode code; Unicode *u = nullptr; int uLen; double dx, dy, originX, originY; while (len > 0) { int n = font->getNextChar(p, len, &code, &u, &uLen, &dx, &dy, &originX, &originY); p += n; len -= n; if (!u) break; str += QChar(*u); } str = str.simplified(); if (str.isEmpty()) return; // escape special characters str.replace('&', "&"); str.replace('<', "<"); str.replace('>', ">"); double x = state->getCurX(); double y = state->getCurY(); const double * ctm = state->getCTM(); QMatrix transform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]); QMatrix mirror; mirror.translate(x, y); mirror.scale(1.0, -1.0); mirror.translate(-x, -y); transform = mirror * transform; bool writeTransform = true; if (transform.m11() == 1.0 && transform.m12() == 0.0 && transform.m21() == 0.0 && transform.m22() == 1.0) { writeTransform = false; x += transform.dx(); y += transform.dy(); } *d->body << "body << " x=\"" << x << "px\""; *d->body << " y=\"" << y << "px\""; if (font && font->getFamily()) { *d->body << " font-family=\"" << QString::fromLatin1(font->getFamily()->getCString()) << "\""; //debugPdf << "font family:" << QString::fromLatin1( font->getFamily()->getCString() ); } else if (font && font->getName()) { *d->body << " font-family=\"" << QString::fromLatin1(font->getName()->getCString()) << "\""; //debugPdf << "font name:" << QString::fromLatin1( font->getName()->getCString() ); } *d->body << " font-size=\"" << qMax(state->getFontSize(), state->getTransformedFontSize()) << "px\""; if (writeTransform) *d->body << " transform=\"" << convertMatrix(transform) << "\""; // fill if (!(render & 1)) *d->body << printFill(); // stroke if ((render & 3) == 1 || (render & 3) == 2) *d->body << printStroke(); *d->body << ">"; *d->body << str; *d->body << "" << endl; } void SvgOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, - GBool /*interpolate*/, int *maskColors, GBool inlineImg) + bool /*interpolate*/, int *maskColors, bool inlineImg) { ImageStream * imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); unsigned int *dest = 0; unsigned char * buffer = new unsigned char[width * height * 4]; QImage * image = 0; if (maskColors) { for (int y = 0; y < height; y++) { dest = (unsigned int *)(buffer + y * 4 * width); Guchar * pix = imgStr->getLine(); colorMap->getRGBLine(pix, dest, width); for (int x = 0; x < width; x++) { for (int i = 0; i < colorMap->getNumPixelComps(); ++i) { if (pix[i] < maskColors[2*i] * 255 || pix[i] > maskColors[2*i+1] * 255) { *dest = *dest | 0xff000000; break; } } pix += colorMap->getNumPixelComps(); dest++; } } image = new QImage(buffer, width, height, QImage::Format_ARGB32); } else { 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()) { debugPdf << "Null image"; delete imgStr; delete[] buffer; delete image; return; } const double * ctm = state->getCTM(); QMatrix m; m.setMatrix(ctm[0] / width, ctm[1] / width, -ctm[2] / height, -ctm[3] / height, ctm[2] + ctm[4], ctm[3] + ctm[5]); QByteArray ba; QBuffer device(&ba); device.open(QIODevice::WriteOnly); if (image->save(&device, "PNG")) { *d->body << "body << " transform=\"" << convertMatrix(m) << "\""; *d->body << " width=\"" << width << "px\""; *d->body << " height=\"" << height << "px\""; *d->body << " xlink:href=\"data:image/png;base64," << ba.toBase64() << "\""; *d->body << " />" << endl; } delete image; delete[] buffer; delete imgStr; } diff --git a/filters/karbon/pdf/SvgOutputDev.h b/filters/karbon/pdf/SvgOutputDev.h index 422027c4fd6..df2805c86a5 100644 --- a/filters/karbon/pdf/SvgOutputDev.h +++ b/filters/karbon/pdf/SvgOutputDev.h @@ -1,92 +1,92 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SVGOUTPUTDEV_H #define SVGOUTPUTDEV_H // Don't show this warning: it's an issue in poppler #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-parameter" #endif #include #include #include class GfxPath; class QMatrix; class GooString; /** * Poppler svg output device base on code from popplers ArthurOutputDev * */ class SvgOutputDev : public OutputDev { public: explicit SvgOutputDev(const QString &fileName); virtual ~SvgOutputDev(); - GBool isOk(); + bool isOk(); - GBool upsideDown() override; - GBool useDrawChar() override; - GBool interpretType3Chars() override; + bool upsideDown() override; + bool useDrawChar() override; + bool interpretType3Chars() override; void startPage(int pageNum, GfxState *state, XRef *xref) override; void endPage() override; // path painting void stroke(GfxState * state) override; void fill(GfxState * state) override; void eoFill(GfxState *state) override; // text void drawString(GfxState * state, const GooString * s) override; // images void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, - GBool interpolate, int *maskColors, GBool inlineImg) override; + bool interpolate, int *maskColors, bool inlineImg) override; // styles void updateAll(GfxState *state) override; void updateFillColor(GfxState *state) override; void updateStrokeColor(GfxState *state) override; void updateFillOpacity(GfxState *state) override; void updateStrokeOpacity(GfxState *state) override; void updateLineJoin(GfxState *state) override; void updateLineCap(GfxState *state) override; void updateMiterLimit(GfxState *state) override; void updateLineWidth(GfxState *state) override; /// Dumps content to svg file void dumpContent(); private: QString convertPath(GfxPath *path); QString convertMatrix(const QMatrix &matrix); QString convertMatrix(const double * matrix); QString printFill(); QString printStroke(); class Private; Private * const d; }; #endif // SVGOUTPUTDEV_H