Commit 89cf21b2 authored by M  B 's avatar M  B  Committed by Albert Astals Cid
Browse files

Add support for image sizes in markdowns

The discount markdown parser supports parsing explicit image sizes in markdown, but we ignore them and replace them with the actual image dimensions. With this patch, any specified image sizes are respected.
parent 511fc7ac
Pipeline #31394 passed with stage
in 16 minutes and 20 seconds
......@@ -106,3 +106,12 @@ ecm_add_test(signatureformtest.cpp
TEST_NAME "signatureformtest"
LINK_LIBRARIES Qt5::Test okularcore
)
find_package(Discount "2")
if(discount_FOUND)
ecm_add_test(markdowntest.cpp ../generators/markdown/converter.cpp
TEST_NAME "markdowntest"
LINK_LIBRARIES Qt5::Test okularcore KF5::I18n discount::Lib
)
endif()
# Test for specifying image sizes in markdown
(c)
## small image
* no explicit size:
![potato](potato.jpg)
* only width specified `=100x`:
![potato](potato.jpg =100x)
* only height specified `=x100`:
![potato](potato.jpg =x100)
* both specified `=100x100`:
![potato](potato.jpg =100x100)
* only width, using html `4200x`:
<img src="potato.jpg" alt="potato" width="4200"/>
* both specified, using html `4200x4200`:
<img src="potato.jpg" alt="potato" width="4200" height="4200"/>
## wide image
* no explicit size:
![1500x300](1500x300.png)
* only width specified `=100x`:
![1500x300](1500x300.png =100x)
* only height specified `=x100`:
![1500x300](1500x300.png =x100)
* both specified `=100x100`:
![1500x300](1500x300.png =100x100)
* only height specified, using html `x4200`:
<img src="1500x300.png" alt="1500x300" height="4200"/>
* both specified, using html `4200x4200`:
<img src="1500x300.png" alt="1500x300" width="4200" height="4200"/>
## tall image
* no explicit size:
![300x1500](300x1500.png)
* only width specified `=100x`:
![300x1500](300x1500.png =100x)
* only height specified `=x100`:
![300x1500](300x1500.png =x100)
* both specified `=100x100`:
![300x1500](300x1500.png =100x100)
* both specified, using html `4200x4200`:
<img src="300x1500.png" alt="300x1500" width="4200" height="4200"/>
/***************************************************************************
* Copyright (C) 2020 by Markus Brenneis <support.gulp21+kde@gmail.com> *
* *
* 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 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include <QtTest>
#include "../settings_core.h"
#include "core/document.h"
#include "generators/markdown/converter.h"
#include <QMimeDatabase>
#include <QMimeType>
#include <QTextDocument>
class MarkdownTest : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void testFancyPantsEnabled();
void testFancyPantsDisabled();
void testImageSizes();
private:
void findImages(QTextFrame *parent, QVector<QTextImageFormat> &images);
void findImages(const QTextBlock &parent, QVector<QTextImageFormat> &images);
};
void MarkdownTest::initTestCase()
{
Okular::SettingsCore::instance(QStringLiteral("markdowntest"));
}
void MarkdownTest::testFancyPantsEnabled()
{
Markdown::Converter converter;
converter.setFancyPantsEnabled(true);
QTextDocument *document = converter.convert(QStringLiteral(KDESRCDIR "data/imageSizes.md"));
QTextFrame::iterator secondFrame = ++(document->rootFrame()->begin());
QVERIFY(secondFrame.currentBlock().text().startsWith(QStringLiteral("©")));
}
void MarkdownTest::testFancyPantsDisabled()
{
Markdown::Converter converter;
converter.setFancyPantsEnabled(false);
QTextDocument *document = converter.convert(QStringLiteral(KDESRCDIR "data/imageSizes.md"));
QTextFrame::iterator secondFrame = ++(document->rootFrame()->begin());
QVERIFY(secondFrame.currentBlock().text().startsWith(QStringLiteral("(c)")));
}
void MarkdownTest::testImageSizes()
{
Markdown::Converter converter;
QTextDocument *document = converter.convert(QStringLiteral(KDESRCDIR "data/imageSizes.md"));
QTextFrame *parent = document->rootFrame();
QVector<QTextImageFormat> images;
findImages(parent, images);
QCOMPARE(images.size(), 17);
qreal expectedSizes[][2] = {// width, height
// small image
{412, 349},
{100, 84.70873786407767},
{118.0515759312321, 100},
{100, 100},
{890, 753.9077669902913},
{890, 890},
// wide image
{890, 178},
{100, 20},
{500, 100},
{100, 100},
{890, 178},
{890, 890},
// tall image
{300, 1500},
{100, 500},
{20, 100},
{100, 100},
{890, 890}};
for (int i = 0; i < images.size(); i++) {
QCOMPARE(images[i].width(), expectedSizes[i][0]);
QCOMPARE(images[i].height(), expectedSizes[i][1]);
}
}
void MarkdownTest::findImages(QTextFrame *parent, QVector<QTextImageFormat> &images)
{
for (QTextFrame::iterator it = parent->begin(); !it.atEnd(); ++it) {
QTextFrame *textFrame = it.currentFrame();
const QTextBlock textBlock = it.currentBlock();
if (textFrame) {
findImages(textFrame, images);
} else if (textBlock.isValid()) {
findImages(textBlock, images);
}
}
}
void MarkdownTest::findImages(const QTextBlock &parent, QVector<QTextImageFormat> &images)
{
for (QTextBlock::iterator it = parent.begin(); !it.atEnd(); ++it) {
const QTextFragment textFragment = it.fragment();
if (textFragment.isValid()) {
const QTextCharFormat textCharFormat = textFragment.charFormat();
if (textCharFormat.isImageFormat()) {
images.append(textCharFormat.toImageFormat());
}
}
}
}
QTEST_MAIN(MarkdownTest)
#include "markdowntest.moc"
......@@ -9,8 +9,6 @@
#include "converter.h"
#include "generator_md.h"
#include <KLocalizedString>
#include <QDir>
......@@ -41,10 +39,16 @@ extern "C" {
#define MKD_AUTOLINK 0
#endif
#define PAGE_WIDTH 980
#define PAGE_HEIGHT 1307
#define PAGE_MARGIN 45
#define CONTENT_WIDTH (PAGE_WIDTH - 2 * PAGE_MARGIN)
using namespace Markdown;
Converter::Converter()
: m_markdownFile(nullptr)
, m_isFancyPantsEnabled(true)
{
}
......@@ -96,7 +100,7 @@ QTextDocument *Converter::convertOpenFile()
MMIOT *markdownHandle = mkd_in(m_markdownFile, 0);
int flags = MKD_FENCEDCODE | MKD_GITHUBTAGS | MKD_AUTOLINK | MKD_TOC | MKD_IDANCHOR;
if (!MarkdownGenerator::isFancyPantsEnabled())
if (!m_isFancyPantsEnabled)
flags |= MKD_NOPANTS;
if (!mkd_compile(markdownHandle, flags)) {
emit error(i18n("Failed to compile the Markdown document."), -1);
......@@ -109,14 +113,15 @@ QTextDocument *Converter::convertOpenFile()
const QString html = QString::fromUtf8(htmlDocument, size);
QTextDocument *textDocument = new QTextDocument;
textDocument->setPageSize(QSizeF(980, 1307));
textDocument->setPageSize(QSizeF(PAGE_WIDTH, PAGE_HEIGHT));
textDocument->setHtml(html);
textDocument->setDefaultFont(generator()->generalSettings()->font());
if (generator())
textDocument->setDefaultFont(generator()->generalSettings()->font());
mkd_cleanup(markdownHandle);
QTextFrameFormat frameFormat;
frameFormat.setMargin(45);
frameFormat.setMargin(PAGE_MARGIN);
QTextFrame *rootFrame = textDocument->rootFrame();
rootFrame->setFrameFormat(frameFormat);
......@@ -189,16 +194,13 @@ void Converter::convertImages(const QTextBlock &parent, const QDir &dir, QTextDo
QTextImageFormat format;
const qreal specifiedHeight = textCharFormat.toImageFormat().height();
const qreal specifiedWidth = textCharFormat.toImageFormat().width();
format.setName(QDir::cleanPath(dir.absoluteFilePath(textCharFormat.toImageFormat().name())));
const QImage img = QImage(format.name());
if (img.width() > 890) {
format.setWidth(890);
format.setHeight(img.height() * 890. / img.width());
} else {
format.setWidth(img.width());
format.setHeight(img.height());
}
setImageSize(format, specifiedWidth, specifiedHeight, img.width(), img.height());
QTextCursor cursor(textDocument);
cursor.setPosition(textFragment.position(), QTextCursor::MoveAnchor);
......@@ -209,3 +211,30 @@ void Converter::convertImages(const QTextBlock &parent, const QDir &dir, QTextDo
}
}
}
void Converter::setImageSize(QTextImageFormat &format, const qreal specifiedWidth, const qreal specifiedHeight, const qreal originalWidth, const qreal originalHeight)
{
qreal width = 0;
qreal height = 0;
const bool hasSpecifiedSize = specifiedHeight > 0 || specifiedWidth > 0;
if (hasSpecifiedSize) {
width = specifiedWidth;
height = specifiedHeight;
if (width == 0 && originalHeight > 0) {
width = originalWidth * height / originalHeight;
} else if (height == 0 && originalWidth > 0) {
height = originalHeight * width / originalWidth;
}
} else {
width = originalWidth;
height = originalHeight;
}
if (width > CONTENT_WIDTH) {
height = height * CONTENT_WIDTH / width;
width = CONTENT_WIDTH;
}
format.setWidth(width);
format.setHeight(height);
}
......@@ -32,6 +32,15 @@ public:
void convertAgain();
void setFancyPantsEnabled(bool b)
{
m_isFancyPantsEnabled = b;
}
bool isFancyPantsEnabled() const
{
return m_isFancyPantsEnabled;
}
QTextDocument *convertOpenFile();
private:
......@@ -39,9 +48,11 @@ private:
void extractLinks(const QTextBlock &parent, QHash<QString, QTextFragment> &internalLinks, QHash<QString, QTextBlock> &documentAnchors);
void convertImages(QTextFrame *parent, const QDir &dir, QTextDocument *textDocument);
void convertImages(const QTextBlock &parent, const QDir &dir, QTextDocument *textDocument);
void setImageSize(QTextImageFormat &format, const qreal specifiedWidth, const qreal specifiedHeight, const qreal originalWidth, const qreal originalHeight);
FILE *m_markdownFile;
QDir m_fileDir;
bool m_isFancyPantsEnabled;
};
}
......
......@@ -20,27 +20,27 @@
OKULAR_EXPORT_PLUGIN(MarkdownGenerator, "libokularGenerator_md.json")
bool MarkdownGenerator::s_isFancyPantsEnabled = true;
bool MarkdownGenerator::s_wasFancyPantsEnabled = true;
MarkdownGenerator::MarkdownGenerator(QObject *parent, const QVariantList &args)
: Okular::TextDocumentGenerator(new Markdown::Converter, QStringLiteral("okular_markdown_generator_settings"), parent, args)
{
Okular::TextDocumentSettings *mdSettings = generalSettings();
mdSettings->addItemBool(QStringLiteral("SmartyPants"), s_isFancyPantsEnabled, true);
mdSettings->addItemBool(QStringLiteral("SmartyPants"), m_isFancyPantsConfigEnabled, true);
mdSettings->load();
s_wasFancyPantsEnabled = s_isFancyPantsEnabled;
m_wasFancyPantsConfigEnabled = m_isFancyPantsConfigEnabled;
Markdown::Converter *c = static_cast<Markdown::Converter *>(converter());
c->setFancyPantsEnabled(m_isFancyPantsConfigEnabled);
}
bool MarkdownGenerator::reparseConfig()
{
const bool textDocumentGeneratorChangedConfig = Okular::TextDocumentGenerator::reparseConfig();
if (s_wasFancyPantsEnabled != s_isFancyPantsEnabled) {
s_wasFancyPantsEnabled = s_isFancyPantsEnabled;
if (m_wasFancyPantsConfigEnabled != m_isFancyPantsConfigEnabled) {
m_wasFancyPantsConfigEnabled = m_isFancyPantsConfigEnabled;
Markdown::Converter *c = static_cast<Markdown::Converter *>(converter());
c->setFancyPantsEnabled(m_isFancyPantsConfigEnabled);
c->convertAgain();
setTextDocument(c->document());
......
......@@ -24,14 +24,9 @@ public:
bool reparseConfig() override;
void addPages(KConfigDialog *dlg) override;
static bool isFancyPantsEnabled()
{
return s_isFancyPantsEnabled;
}
private:
static bool s_isFancyPantsEnabled;
static bool s_wasFancyPantsEnabled;
bool m_isFancyPantsConfigEnabled = true;
bool m_wasFancyPantsConfigEnabled = true;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment