mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
embed images in exported html
This commit is contained in:
parent
26ecf08f4a
commit
cba8b1c047
@ -313,11 +313,23 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
|
|||||||
m_embedStyleCB = new QCheckBox(tr("Embed CSS styles"), this);
|
m_embedStyleCB = new QCheckBox(tr("Embed CSS styles"), this);
|
||||||
m_embedStyleCB->setToolTip(tr("Embed CSS styles in HTML file"));
|
m_embedStyleCB->setToolTip(tr("Embed CSS styles in HTML file"));
|
||||||
|
|
||||||
|
// Embed images as data URI.
|
||||||
|
m_embedImagesCB = new QCheckBox(tr("Embed images"), this);
|
||||||
|
m_embedImagesCB->setToolTip(tr("Embed images as data URI"));
|
||||||
|
|
||||||
// Complete HTML.
|
// Complete HTML.
|
||||||
m_completeHTMLCB = new QCheckBox(tr("Complete page"), this);
|
m_completeHTMLCB = new QCheckBox(tr("Complete page"), this);
|
||||||
m_completeHTMLCB->setToolTip(tr("Export the whole web page along with pictures "
|
m_completeHTMLCB->setToolTip(tr("Export the whole web page along with pictures "
|
||||||
"which may not keep the HTML link structure of "
|
"which may not keep the HTML link structure of "
|
||||||
"the original page"));
|
"the original page"));
|
||||||
|
connect(m_completeHTMLCB, &QCheckBox::stateChanged,
|
||||||
|
this, [this](int p_state) {
|
||||||
|
bool checked = p_state == Qt::Checked;
|
||||||
|
m_embedImagesCB->setEnabled(checked);
|
||||||
|
if (!checked) {
|
||||||
|
m_embedImagesCB->setChecked(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Mime HTML.
|
// Mime HTML.
|
||||||
m_mimeHTMLCB = new QCheckBox(tr("MIME HTML"), this);
|
m_mimeHTMLCB = new QCheckBox(tr("MIME HTML"), this);
|
||||||
@ -332,6 +344,7 @@ QWidget *VExportDialog::setupHTMLAdvancedSettings()
|
|||||||
QFormLayout *advLayout = new QFormLayout();
|
QFormLayout *advLayout = new QFormLayout();
|
||||||
advLayout->addRow(m_embedStyleCB);
|
advLayout->addRow(m_embedStyleCB);
|
||||||
advLayout->addRow(m_completeHTMLCB);
|
advLayout->addRow(m_completeHTMLCB);
|
||||||
|
advLayout->addRow(m_embedImagesCB);
|
||||||
advLayout->addRow(m_mimeHTMLCB);
|
advLayout->addRow(m_mimeHTMLCB);
|
||||||
|
|
||||||
advLayout->setContentsMargins(0, 0, 0, 0);
|
advLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
@ -435,6 +448,8 @@ void VExportDialog::initUIFields(MarkdownConverterType p_renderer)
|
|||||||
|
|
||||||
m_completeHTMLCB->setChecked(s_opt.m_htmlOpt.m_completeHTML);
|
m_completeHTMLCB->setChecked(s_opt.m_htmlOpt.m_completeHTML);
|
||||||
|
|
||||||
|
m_embedImagesCB->setChecked(s_opt.m_htmlOpt.m_embedImages);
|
||||||
|
|
||||||
m_mimeHTMLCB->setChecked(s_opt.m_htmlOpt.m_mimeHTML);
|
m_mimeHTMLCB->setChecked(s_opt.m_htmlOpt.m_mimeHTML);
|
||||||
|
|
||||||
m_tableOfContentsCB->setChecked(s_opt.m_pdfOpt.m_enableTableOfContents);
|
m_tableOfContentsCB->setChecked(s_opt.m_pdfOpt.m_enableTableOfContents);
|
||||||
@ -534,6 +549,7 @@ void VExportDialog::startExport()
|
|||||||
m_wkExtraArgsEdit->text()),
|
m_wkExtraArgsEdit->text()),
|
||||||
ExportHTMLOption(m_embedStyleCB->isChecked(),
|
ExportHTMLOption(m_embedStyleCB->isChecked(),
|
||||||
m_completeHTMLCB->isChecked(),
|
m_completeHTMLCB->isChecked(),
|
||||||
|
m_embedImagesCB->isChecked(),
|
||||||
m_mimeHTMLCB->isChecked()),
|
m_mimeHTMLCB->isChecked()),
|
||||||
ExportCustomOption((ExportCustomOption::SourceFormat)
|
ExportCustomOption((ExportCustomOption::SourceFormat)
|
||||||
m_customSrcFormatCB->currentData().toInt(),
|
m_customSrcFormatCB->currentData().toInt(),
|
||||||
|
@ -57,21 +57,25 @@ struct ExportHTMLOption
|
|||||||
ExportHTMLOption()
|
ExportHTMLOption()
|
||||||
: m_embedCssStyle(true),
|
: m_embedCssStyle(true),
|
||||||
m_completeHTML(true),
|
m_completeHTML(true),
|
||||||
|
m_embedImages(true),
|
||||||
m_mimeHTML(false)
|
m_mimeHTML(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportHTMLOption(bool p_embedCssStyle,
|
ExportHTMLOption(bool p_embedCssStyle,
|
||||||
bool p_completeHTML,
|
bool p_completeHTML,
|
||||||
|
bool p_embedImages,
|
||||||
bool p_mimeHTML)
|
bool p_mimeHTML)
|
||||||
: m_embedCssStyle(p_embedCssStyle),
|
: m_embedCssStyle(p_embedCssStyle),
|
||||||
m_completeHTML(p_completeHTML),
|
m_completeHTML(p_completeHTML),
|
||||||
|
m_embedImages(p_embedImages),
|
||||||
m_mimeHTML(p_mimeHTML)
|
m_mimeHTML(p_mimeHTML)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_embedCssStyle;
|
bool m_embedCssStyle;
|
||||||
bool m_completeHTML;
|
bool m_completeHTML;
|
||||||
|
bool m_embedImages;
|
||||||
bool m_mimeHTML;
|
bool m_mimeHTML;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -431,7 +435,9 @@ private:
|
|||||||
|
|
||||||
QCheckBox *m_embedStyleCB;
|
QCheckBox *m_embedStyleCB;
|
||||||
|
|
||||||
QCheckBox *m_completeHTMLCB;;
|
QCheckBox *m_completeHTMLCB;
|
||||||
|
|
||||||
|
QCheckBox *m_embedImagesCB;
|
||||||
|
|
||||||
QCheckBox *m_mimeHTMLCB;
|
QCheckBox *m_mimeHTMLCB;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QImageReader>
|
||||||
|
|
||||||
#include "vpalette.h"
|
#include "vpalette.h"
|
||||||
#include "vconfigmanager.h"
|
#include "vconfigmanager.h"
|
||||||
@ -924,3 +925,40 @@ QString VWebUtils::copyResource(const QUrl &p_url, const QString &p_folder) cons
|
|||||||
|
|
||||||
return succ ? targetFile : QString();
|
return succ ? targetFile : QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString VWebUtils::dataURI(const QUrl &p_url) const
|
||||||
|
{
|
||||||
|
QString uri;
|
||||||
|
Q_ASSERT(!p_url.isRelative());
|
||||||
|
QString file = p_url.isLocalFile() ? p_url.toLocalFile() : p_url.toString();
|
||||||
|
QString suffix(QFileInfo(file).suffix().toLower());
|
||||||
|
|
||||||
|
if (!QImageReader::supportedImageFormats().contains(suffix.toLatin1())) {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
if (p_url.scheme() == "https" || p_url.scheme() == "http") {
|
||||||
|
// Download it.
|
||||||
|
data = VDownloader::downloadSync(p_url);
|
||||||
|
} else if (QFileInfo::exists(file)) {
|
||||||
|
QFile fi(file);
|
||||||
|
if (fi.open(QIODevice::ReadOnly)) {
|
||||||
|
data = fi.readAll();
|
||||||
|
fi.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix == "svg") {
|
||||||
|
uri = QString("data:image/svg+xml;utf8,%1").arg(QString::fromUtf8(data));
|
||||||
|
uri.replace('\r', "").replace('\n', "");
|
||||||
|
} else {
|
||||||
|
uri = QString("data:image/%1;base64,%2").arg(suffix).arg(QString::fromUtf8(data.toBase64()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
@ -25,6 +25,9 @@ public:
|
|||||||
// Return the target file path on success or empty string on failure.
|
// Return the target file path on success or empty string on failure.
|
||||||
QString copyResource(const QUrl &p_url, const QString &p_folder) const;
|
QString copyResource(const QUrl &p_url, const QString &p_folder) const;
|
||||||
|
|
||||||
|
// Return a dataURI of @p_url if it is an image.
|
||||||
|
QString dataURI(const QUrl &p_url) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CopyTargetAction
|
struct CopyTargetAction
|
||||||
{
|
{
|
||||||
|
@ -336,7 +336,8 @@ bool VExporter::exportToPDFViaWK(VDocument *p_webDocument,
|
|||||||
p_styleContent,
|
p_styleContent,
|
||||||
p_bodyContent,
|
p_bodyContent,
|
||||||
true,
|
true,
|
||||||
true)) {
|
true,
|
||||||
|
false)) {
|
||||||
pdfExported = -1;
|
pdfExported = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -395,7 +396,8 @@ bool VExporter::exportToCustom(VDocument *p_webDocument,
|
|||||||
p_styleContent,
|
p_styleContent,
|
||||||
p_bodyContent,
|
p_bodyContent,
|
||||||
true,
|
true,
|
||||||
true)) {
|
true,
|
||||||
|
false)) {
|
||||||
exported = -1;
|
exported = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -561,7 +563,8 @@ bool VExporter::exportToHTML(VDocument *p_webDocument,
|
|||||||
p_styleContent,
|
p_styleContent,
|
||||||
p_bodyContent,
|
p_bodyContent,
|
||||||
p_opt.m_embedCssStyle,
|
p_opt.m_embedCssStyle,
|
||||||
p_opt.m_completeHTML)) {
|
p_opt.m_completeHTML,
|
||||||
|
p_opt.m_embedImages)) {
|
||||||
htmlExported = -1;
|
htmlExported = -1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -610,6 +613,33 @@ bool VExporter::fixStyleResources(const QString &p_folder,
|
|||||||
return altered;
|
return altered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VExporter::embedStyleResources(QString &p_html)
|
||||||
|
{
|
||||||
|
bool altered = false;
|
||||||
|
QRegExp reg("\\burl\\(\"((file|qrc):[^\"\\)]+)\"\\);");
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int idx = p_html.indexOf(reg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dataURI = g_webUtils->dataURI(QUrl(reg.cap(1)));
|
||||||
|
if (dataURI.isEmpty()) {
|
||||||
|
pos = idx + reg.matchedLength();
|
||||||
|
} else {
|
||||||
|
// Replace the url string in html.
|
||||||
|
QString newUrl = QString("url('%1');").arg(dataURI);
|
||||||
|
p_html.replace(idx, reg.matchedLength(), newUrl);
|
||||||
|
pos = idx + newUrl.size();
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
bool VExporter::fixBodyResources(const QUrl &p_baseUrl,
|
bool VExporter::fixBodyResources(const QUrl &p_baseUrl,
|
||||||
const QString &p_folder,
|
const QString &p_folder,
|
||||||
QString &p_html)
|
QString &p_html)
|
||||||
@ -651,6 +681,45 @@ bool VExporter::fixBodyResources(const QUrl &p_baseUrl,
|
|||||||
return altered;
|
return altered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VExporter::embedBodyResources(const QUrl &p_baseUrl, QString &p_html)
|
||||||
|
{
|
||||||
|
bool altered = false;
|
||||||
|
if (p_baseUrl.isEmpty()) {
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRegExp reg("<img ([^>]*)src=\"([^\"]+)\"([^>]*)>");
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < p_html.size()) {
|
||||||
|
int idx = p_html.indexOf(reg, pos);
|
||||||
|
if (idx == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg.cap(2).isEmpty()) {
|
||||||
|
pos = idx + reg.matchedLength();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl srcUrl(p_baseUrl.resolved(reg.cap(2)));
|
||||||
|
QString dataURI = g_webUtils->dataURI(srcUrl);
|
||||||
|
if (dataURI.isEmpty()) {
|
||||||
|
pos = idx + reg.matchedLength();
|
||||||
|
} else {
|
||||||
|
// Replace the url string in html.
|
||||||
|
QString newUrl = QString("<img %1src='%2'%3>").arg(reg.cap(1))
|
||||||
|
.arg(dataURI)
|
||||||
|
.arg(reg.cap(3));
|
||||||
|
p_html.replace(idx, reg.matchedLength(), newUrl);
|
||||||
|
pos = idx + newUrl.size();
|
||||||
|
altered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return altered;
|
||||||
|
}
|
||||||
|
|
||||||
QString VExporter::getResourceRelativePath(const QString &p_file)
|
QString VExporter::getResourceRelativePath(const QString &p_file)
|
||||||
{
|
{
|
||||||
int idx = p_file.lastIndexOf('/');
|
int idx = p_file.lastIndexOf('/');
|
||||||
@ -901,7 +970,8 @@ bool VExporter::outputToHTMLFile(const QString &p_file,
|
|||||||
const QString &p_styleContent,
|
const QString &p_styleContent,
|
||||||
const QString &p_bodyContent,
|
const QString &p_bodyContent,
|
||||||
bool p_embedCssStyle,
|
bool p_embedCssStyle,
|
||||||
bool p_completeHTML)
|
bool p_completeHTML,
|
||||||
|
bool p_embedImages)
|
||||||
{
|
{
|
||||||
QFile file(p_file);
|
QFile file(p_file);
|
||||||
if (!file.open(QFile::WriteOnly)) {
|
if (!file.open(QFile::WriteOnly)) {
|
||||||
@ -916,7 +986,7 @@ bool VExporter::outputToHTMLFile(const QString &p_file,
|
|||||||
QString html(m_exportHtmlTemplate);
|
QString html(m_exportHtmlTemplate);
|
||||||
if (!p_styleContent.isEmpty() && p_embedCssStyle) {
|
if (!p_styleContent.isEmpty() && p_embedCssStyle) {
|
||||||
QString content(p_styleContent);
|
QString content(p_styleContent);
|
||||||
fixStyleResources(resFolderPath, content);
|
embedStyleResources(content);
|
||||||
html.replace(HtmlHolder::c_styleHolder, content);
|
html.replace(HtmlHolder::c_styleHolder, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,7 +996,12 @@ bool VExporter::outputToHTMLFile(const QString &p_file,
|
|||||||
|
|
||||||
if (p_completeHTML) {
|
if (p_completeHTML) {
|
||||||
QString content(p_bodyContent);
|
QString content(p_bodyContent);
|
||||||
fixBodyResources(m_baseUrl, resFolderPath, content);
|
if (p_embedImages) {
|
||||||
|
embedBodyResources(m_baseUrl, content);
|
||||||
|
} else {
|
||||||
|
fixBodyResources(m_baseUrl, resFolderPath, content);
|
||||||
|
}
|
||||||
|
|
||||||
html.replace(HtmlHolder::c_bodyHolder, content);
|
html.replace(HtmlHolder::c_bodyHolder, content);
|
||||||
} else {
|
} else {
|
||||||
html.replace(HtmlHolder::c_bodyHolder, p_bodyContent);
|
html.replace(HtmlHolder::c_bodyHolder, p_bodyContent);
|
||||||
|
@ -133,24 +133,33 @@ private:
|
|||||||
|
|
||||||
int startProcess(const QString &p_cmd);
|
int startProcess(const QString &p_cmd);
|
||||||
|
|
||||||
|
// @p_embedImages: embed <img> as data URI.
|
||||||
bool outputToHTMLFile(const QString &p_file,
|
bool outputToHTMLFile(const QString &p_file,
|
||||||
const QString &p_headContent,
|
const QString &p_headContent,
|
||||||
const QString &p_styleContent,
|
const QString &p_styleContent,
|
||||||
const QString &p_bodyContent,
|
const QString &p_bodyContent,
|
||||||
bool p_embedCssStyle,
|
bool p_embedCssStyle,
|
||||||
bool p_completeHTML);
|
bool p_completeHTML,
|
||||||
|
bool p_embedImages);
|
||||||
|
|
||||||
// Fix @p_html's resources like url("...") with "file" or "qrc" schema.
|
// Fix @p_html's resources like url("...") with "file" or "qrc" schema.
|
||||||
// Copy the resource to @p_folder and fix the url string.
|
// Copy the resource to @p_folder and fix the url string.
|
||||||
static bool fixStyleResources(const QString &p_folder,
|
static bool fixStyleResources(const QString &p_folder,
|
||||||
QString &p_html);
|
QString &p_html);
|
||||||
|
|
||||||
|
// Fix @p_html's resources like url("...") with "file" or "qrc" schema.
|
||||||
|
// Embed the image data in data URIs.
|
||||||
|
static bool embedStyleResources(QString &p_html);
|
||||||
|
|
||||||
// Fix @p_html's resources like <img>.
|
// Fix @p_html's resources like <img>.
|
||||||
// Copy the resource to @p_folder and fix the url string.
|
// Copy the resource to @p_folder and fix the url string.
|
||||||
static bool fixBodyResources(const QUrl &p_baseUrl,
|
static bool fixBodyResources(const QUrl &p_baseUrl,
|
||||||
const QString &p_folder,
|
const QString &p_folder,
|
||||||
QString &p_html);
|
QString &p_html);
|
||||||
|
|
||||||
|
// Embed @p_html's resources like <img>.
|
||||||
|
static bool embedBodyResources(const QUrl &p_baseUrl, QString &p_html);
|
||||||
|
|
||||||
static QString getResourceRelativePath(const QString &p_file);
|
static QString getResourceRelativePath(const QString &p_file);
|
||||||
|
|
||||||
QPageLayout m_pageLayout;
|
QPageLayout m_pageLayout;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user