// -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
// vi:set ts=4 sts=4 sw=4 noet :
//
// Copyright 2010, 2011 wkhtmltopdf authors
//
// This file is part of wkhtmltopdf.
//
// wkhtmltopdf is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// wkhtmltopdf 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 Lesser General Public License
// along with wkhtmltopdf. If not, see .
#include "imageconverter_p.hh"
#include "imagesettings.hh"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef Q_OS_WIN32
#include
#include
#endif
namespace wkhtmltopdf {
ImageConverterPrivate::ImageConverterPrivate(ImageConverter & o, wkhtmltopdf::settings::ImageGlobal & s, const QString * data):
settings(s),
loader(s.loadGlobal, true),
out(o) {
out.emitCheckboxSvgs(s.loadPage);
if (data) inputData = *data;
phaseDescriptions.push_back("Loading page");
phaseDescriptions.push_back("Rendering");
phaseDescriptions.push_back("Done");
connect(&loader, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
connect(&loader, SIGNAL(loadFinished(bool)), this, SLOT(pagesLoaded(bool)));
connect(&loader, SIGNAL(error(QString)), this, SLOT(forwardError(QString)));
connect(&loader, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
}
void ImageConverterPrivate::beginConvert() {
error = false;
convertionDone = false;
errorCode = 0;
progressString = "0%";
loaderObject = loader.addResource(settings.in, settings.loadPage, &inputData);
updateWebSettings(loaderObject->page.settings(), settings.web);
currentPhase=0;
emit out. phaseChanged();
loadProgress(0);
loader.load();
}
void ImageConverterPrivate::clearResources() {
loader.clearResources();
}
void ImageConverterPrivate::pagesLoaded(bool ok) {
if (errorCode == 0) errorCode = loader.httpErrorCode();
if (!ok) {
fail();
return;
}
// if fmt is empty try to get it from file extension in out
if (settings.fmt=="") {
if (settings.out == "-")
settings.fmt = "jpg";
else {
QFileInfo fi(settings.out);
settings.fmt = fi.suffix();
}
}
// check whether image format is supported (for writing)
// QImageWriter test;
// test.setFormat(settings.fmt);
// if (!test.canWrite()) {
// if (!settings.quiet)printf("error: file format not supported\n");
// httpErrorCode=DEFAULT;
// return false;
// }
// create webkit frame and load website
currentPhase=1;
emit out. phaseChanged();
loadProgress(0);
QWebFrame * frame = loaderObject->page.mainFrame();
loaderObject->page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
loadProgress(25);
// Calculate a good width for the image
int highWidth=settings.screenWidth;
loaderObject->page.setViewportSize(QSize(highWidth, 10));
if (settings.smartWidth && frame->scrollBarMaximum(Qt::Horizontal) > 0) {
if (highWidth < 10) highWidth=10;
int lowWidth=highWidth;
while (frame->scrollBarMaximum(Qt::Horizontal) > 0 && highWidth < 32000) {
lowWidth = highWidth;
highWidth *= 2;
loaderObject->page.setViewportSize(QSize(highWidth, 10));
}
while (highWidth - lowWidth > 10) {
int t = lowWidth + (highWidth - lowWidth)/2;
loaderObject->page.setViewportSize(QSize(t, 10));
if (frame->scrollBarMaximum(Qt::Horizontal) > 0)
lowWidth = t;
else
highWidth = t;
}
loaderObject->page.setViewportSize(QSize(highWidth, 10));
}
loaderObject->page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
//Set the right height
if (settings.screenHeight > 0)
loaderObject->page.setViewportSize(QSize(highWidth, settings.screenHeight));
else
loaderObject->page.setViewportSize(QSize(highWidth, frame->contentsSize().height()));
QPainter painter;
QSvgGenerator generator;
QImage image;
QFile file;
QBuffer buffer(&outputData);
QIODevice * dev = &file;
bool openOk=true;
// output image
if (settings.out.isEmpty())
dev = &buffer;
else if (settings.out != "-" ) {
file.setFileName(settings.out);
openOk = file.open(QIODevice::WriteOnly);
} else {
#ifdef Q_OS_WIN32
_setmode(_fileno(stdout), _O_BINARY);
#endif
openOk = file.open(stdout, QIODevice::WriteOnly);
}
if (!openOk) {
emit out.error("Could not write to output file");
fail();
}
if (settings.crop.left < 0) settings.crop.left = 0;
if (settings.crop.top < 0) settings.crop.top = 0;
if (settings.crop.width < 0) settings.crop.width = 1000000;
if (settings.crop.height < 0) settings.crop.height = 1000000;
QRect rect = QRect(QPoint(0,0), loaderObject->page.viewportSize()).intersected(
QRect(settings.crop.left,settings.crop.top,settings.crop.width,settings.crop.height));
if (rect.width() == 0 || rect.height() == 0) {
emit out.error("Will not output an empty image");
fail();
}
if (settings.fmt != "svg") {
image = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
painter.begin(&image);
} else {
generator.setOutputDevice(dev);
generator.setSize(rect.size());
generator.setViewBox(QRect(QPoint(0,0),rect.size()));
#ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
generator.setViewBoxClip(true);
#endif
painter.begin(&generator);
}
if (settings.transparent && (settings.fmt == "png" || settings.fmt == "svg")) {
QWebElement e = frame->findFirstElement("body");
e.setStyleProperty("background-color", "transparent");
e.setStyleProperty("background-image", "none");
QPalette pal = loaderObject->page.palette();
pal.setBrush(QPalette::Base, Qt::transparent);
loaderObject->page.setPalette(pal);
} else {
painter.fillRect(QRect(QPoint(0,0),loaderObject->page.viewportSize()), Qt::white);
}
painter.translate(-rect.left(), -rect.top());
frame->render(&painter);
painter.end();
//loadProgress(30);
// perform filter(s)
//if (settings.crop.width > 0 && settings.crop.height > 0)
// image=image.copy(settings.crop.left,settings.crop.top,settings.crop.width,settings.crop.height);
//loadProgress(50);
//if (settings.scale.width > 0 && settings.scale.height > 0) {
// todo: perhaps get more user options to change aspect ration and scaling mode?
// image=image.scaled(settings.scale.width,settings.scale.height,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
//}
//loadProgress(80);
if (settings.fmt != "svg") {
QByteArray fmt=settings.fmt.toLatin1();
if (!image.save(dev,fmt.data(), settings.quality)) {
emit out.error("Could not save image");
fail();
}
}
loadProgress(100);
currentPhase = 2;
emit out.phaseChanged();
convertionDone = true;
emit out.finished(true);
qApp->exit(0); // quit qt's event handling
}
Converter & ImageConverterPrivate::outer() {
return out;
}
ImageConverter::~ImageConverter() {
delete d;
}
ConverterPrivate & ImageConverter::priv() {
return *d;
}
ImageConverter::ImageConverter(wkhtmltopdf::settings::ImageGlobal & s, const QString * data) {
d = new ImageConverterPrivate(*this, s, data);
}
const QByteArray & ImageConverter::output() {
return d->outputData;
}
}