imageconverter.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
  2. // vi:set ts=4 sts=4 sw=4 noet :
  3. // This file is part of wkhtmltopdf.
  4. //
  5. // wkhtmltopdf is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // wkhtmltopdf is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with wkhtmltopdf. If not, see <http://www.gnu.org/licenses/>.
  17. #include "imageconverter_p.hh"
  18. #include "settings.hh"
  19. #include <QObject>
  20. #include <QWebPage>
  21. #include <QWebFrame>
  22. #include <QUrl>
  23. #include <QImage>
  24. #include <QPainter>
  25. #include <QObject>
  26. #include <QEventLoop>
  27. #include <QFileInfo>
  28. #include <QDebug>
  29. #include <qapplication.h>
  30. #include <QSvgGenerator>
  31. namespace wkhtmltopdf {
  32. ImageConverterPrivate::ImageConverterPrivate(ImageConverter & o, wkhtmltopdf::settings::Global & s):
  33. settings(s),
  34. loader(s.loadGlobal),
  35. out(o) {
  36. phaseDescriptions.push_back("Loading page");
  37. phaseDescriptions.push_back("Rendering");
  38. phaseDescriptions.push_back("Done");
  39. connect(&loader, SIGNAL(loadProgress(int)), this, SLOT(loadProgress(int)));
  40. connect(&loader, SIGNAL(loadFinished(bool)), this, SLOT(pagesLoaded(bool)));
  41. connect(&loader, SIGNAL(error(QString)), this, SLOT(forwardError(QString)));
  42. connect(&loader, SIGNAL(warning(QString)), this, SLOT(forwardWarning(QString)));
  43. };
  44. void ImageConverterPrivate::beginConvert() {
  45. error = false;
  46. convertionDone = false;
  47. errorCode = 0;
  48. progressString = "0%";
  49. loaderObject = loader.addResource(settings.in, settings.loadPage);
  50. updateWebSettings(loaderObject->page.settings(), settings.web);
  51. currentPhase=0;
  52. emit out. phaseChanged();
  53. loadProgress(0);
  54. loader.load();
  55. }
  56. void ImageConverterPrivate::clearResources() {
  57. loader.clearResources();
  58. }
  59. void ImageConverterPrivate::pagesLoaded(bool ok) {
  60. if (errorCode == 0) errorCode = loader.httpErrorCode();
  61. if (!ok) {
  62. fail();
  63. return;
  64. }
  65. // if fmt is empty try to get it from file extension in out
  66. if(settings.fmt==""){
  67. if (settings.out == "-")
  68. settings.fmt = "jpg";
  69. else {
  70. QFileInfo fi(settings.out);
  71. settings.fmt = fi.suffix();
  72. }
  73. }
  74. // check whether image format is supported (for writing)
  75. // QImageWriter test;
  76. // test.setFormat(settings.fmt);
  77. // if(!test.canWrite()){
  78. // if(!settings.quiet)printf("error: file format not supported\n");
  79. // httpErrorCode=EFAULT;
  80. // return false;
  81. // }
  82. // create webkit frame and load website
  83. currentPhase=1;
  84. emit out. phaseChanged();
  85. loadProgress(0);
  86. QWebFrame * frame = loaderObject->page.mainFrame();
  87. loaderObject->page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
  88. loadProgress(25);
  89. // Calculate a good width for the image
  90. int highWidth=settings.screenWidth;
  91. loaderObject->page.setViewportSize(QSize(highWidth, 10));
  92. if (settings.smartWidth && frame->scrollBarMaximum(Qt::Horizontal) > 0) {
  93. if (highWidth < 10) highWidth=10;
  94. int lowWidth=highWidth;
  95. while (frame->scrollBarMaximum(Qt::Horizontal) > 0 && highWidth < 32000) {
  96. lowWidth = highWidth;
  97. highWidth *= 2;
  98. loaderObject->page.setViewportSize(QSize(highWidth, 10));
  99. }
  100. while (highWidth - lowWidth > 10) {
  101. int t = lowWidth + (highWidth - lowWidth)/2;
  102. loaderObject->page.setViewportSize(QSize(t, 10));
  103. if (frame->scrollBarMaximum(Qt::Horizontal) > 0)
  104. lowWidth = t;
  105. else
  106. highWidth = t;
  107. }
  108. loaderObject->page.setViewportSize(QSize(highWidth, 10));
  109. }
  110. loaderObject->page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
  111. //Set the right height
  112. loaderObject->page.setViewportSize(QSize(highWidth, frame->contentsSize().height()));
  113. QPainter painter;
  114. QSvgGenerator generator;
  115. QImage image;
  116. QFile file;
  117. bool openOk;
  118. // output image
  119. if (settings.out != "-" ) {
  120. file.setFileName(settings.out);
  121. openOk = file.open(QIODevice::WriteOnly);
  122. } else {
  123. openOk = file.open(stdout, QIODevice::WriteOnly);
  124. }
  125. if (!openOk) {
  126. emit out.error("Could not write to output file");
  127. fail();
  128. }
  129. if (settings.crop.left < 0) settings.crop.left = 0;
  130. if (settings.crop.top < 0) settings.crop.top = 0;
  131. if (settings.crop.width < 0) settings.crop.width = 1000000;
  132. if (settings.crop.height < 0) settings.crop.height = 1000000;
  133. QRect rect = QRect(QPoint(0,0), loaderObject->page.viewportSize()).intersected(
  134. QRect(settings.crop.left,settings.crop.top,settings.crop.width,settings.crop.height));
  135. if (rect.width() == 0 || rect.height() == 0) {
  136. emit out.error("Will not output an empty image");
  137. fail();
  138. }
  139. if (settings.fmt != "svg") {
  140. image = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
  141. painter.begin(&image);
  142. } else {
  143. generator.setOutputDevice(&file);
  144. generator.setSize(rect.size());
  145. generator.setViewBox(QRect(QPoint(0,0),rect.size()));
  146. #ifdef __EXTENSIVE_WKHTMLTOPDF_QT_HACK__
  147. generator.setViewBoxClip(true);
  148. #endif
  149. painter.begin(&generator);
  150. }
  151. if (!settings.transparent || (settings.fmt != "png" && settings.fmt != "svg"))
  152. painter.fillRect(QRect(QPoint(0,0),loaderObject->page.viewportSize()), Qt::white);
  153. painter.translate(-rect.left(), -rect.top());
  154. frame->render(&painter);
  155. painter.end();
  156. //loadProgress(30);
  157. // perform filter(s)
  158. //if (settings.crop.width > 0 && settings.crop.height > 0)
  159. // image=image.copy(settings.crop.left,settings.crop.top,settings.crop.width,settings.crop.height);
  160. //loadProgress(50);
  161. //if (settings.scale.width > 0 && settings.scale.height > 0) {
  162. // todo: perhaps get more user options to change aspect ration and scaling mode?
  163. // image=image.scaled(settings.scale.width,settings.scale.height,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
  164. //}
  165. //loadProgress(80);
  166. if (settings.fmt != "svg") {
  167. QByteArray fmt=settings.fmt.toLatin1();
  168. if (!image.save(&file,fmt.data(), settings.quality)) {
  169. emit out.error("Could not save image");
  170. fail();
  171. }
  172. }
  173. loadProgress(100);
  174. currentPhase = 2;
  175. emit out.phaseChanged();
  176. convertionDone = true;
  177. emit out.finished(true);
  178. qApp->exit(0); // quit qt's event handling
  179. }
  180. Converter & ImageConverterPrivate::outer() {
  181. return out;
  182. }
  183. ImageConverter::~ImageConverter() {
  184. delete d;
  185. }
  186. ConverterPrivate & ImageConverter::priv() {
  187. return *d;
  188. }
  189. ImageConverter::ImageConverter(wkhtmltopdf::settings::Global & s) {
  190. d = new ImageConverterPrivate(*this, s);
  191. }
  192. }