Text highlight tools basics

This commit is contained in:
Jakub Melka 2020-12-11 18:59:39 +01:00
parent 11ad8f2821
commit dc55950050
13 changed files with 856 additions and 18 deletions

View File

@ -19,6 +19,7 @@
#include "pdfdocumentbuilder.h"
#include "pdfdrawwidget.h"
#include "pdfutils.h"
#include "pdfcompiler.h"
#include <QActionGroup>
#include <QInputDialog>
@ -856,4 +857,142 @@ void PDFCreateStampTool::onPointPicked(PDFInteger pageIndex, QPointF pagePoint)
setActive(false);
}
PDFCreateHighlightTextTool::PDFCreateHighlightTextTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, AnnotationType type, QAction* action, QObject* parent) :
BaseClass(proxy, action, parent),
m_toolManager(toolManager),
m_type(type),
m_isCursorOverText(false)
{
updateActions();
}
void PDFCreateHighlightTextTool::drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const
{
Q_UNUSED(compiledPage);
Q_UNUSED(errors);
pdf::PDFTextSelectionPainter textSelectionPainter(&m_textSelection);
textSelectionPainter.draw(painter, pageIndex, layoutGetter, pagePointToDevicePointMatrix);
}
void PDFCreateHighlightTextTool::mousePressEvent(QWidget* widget, QMouseEvent* event)
{
Q_UNUSED(widget);
if (event->button() == Qt::LeftButton)
{
QPointF pagePoint;
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
if (pageIndex != -1)
{
m_selectionInfo.pageIndex = pageIndex;
m_selectionInfo.selectionStartPoint = pagePoint;
event->accept();
}
else
{
m_selectionInfo = SelectionInfo();
}
setSelection(pdf::PDFTextSelection());
updateCursor();
}
}
void PDFCreateHighlightTextTool::mouseReleaseEvent(QWidget* widget, QMouseEvent* event)
{
Q_UNUSED(widget);
if (event->button() == Qt::LeftButton)
{
if (m_selectionInfo.pageIndex != -1)
{
QPointF pagePoint;
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
if (m_selectionInfo.pageIndex == pageIndex)
{
// Jakub Melka: handle the selection
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
setSelection(textLayout.createTextSelection(pageIndex, m_selectionInfo.selectionStartPoint, pagePoint));
}
else
{
setSelection(pdf::PDFTextSelection());
}
m_selectionInfo = SelectionInfo();
event->accept();
updateCursor();
}
}
}
void PDFCreateHighlightTextTool::mouseMoveEvent(QWidget* widget, QMouseEvent* event)
{
Q_UNUSED(widget);
QPointF pagePoint;
const PDFInteger pageIndex = getProxy()->getPageUnderPoint(event->pos(), &pagePoint);
PDFTextLayout textLayout = getProxy()->getTextLayoutCompiler()->getTextLayoutLazy(pageIndex);
m_isCursorOverText = textLayout.isHoveringOverTextBlock(pagePoint);
if (m_selectionInfo.pageIndex != -1)
{
if (m_selectionInfo.pageIndex == pageIndex)
{
// Jakub Melka: handle the selection
setSelection(textLayout.createTextSelection(pageIndex, m_selectionInfo.selectionStartPoint, pagePoint));
}
else
{
setSelection(pdf::PDFTextSelection());
}
event->accept();
}
updateCursor();
}
void PDFCreateHighlightTextTool::setActiveImpl(bool active)
{
BaseClass::setActiveImpl(active);
if (!active)
{
// Just clear the text selection
setSelection(PDFTextSelection());
}
}
void PDFCreateHighlightTextTool::updateCursor()
{
if (isActive())
{
if (m_isCursorOverText)
{
setCursor(QCursor(Qt::IBeamCursor));
}
else
{
setCursor(QCursor(Qt::ArrowCursor));
}
}
}
void PDFCreateHighlightTextTool::setSelection(PDFTextSelection&& textSelection)
{
if (m_textSelection != textSelection)
{
m_textSelection = qMove(textSelection);
getProxy()->repaintNeeded();
}
}
} // namespace pdf

View File

@ -261,6 +261,54 @@ private:
PDFStampAnnotation m_stampAnnotation;
};
/// Tool for highlighting of text in document
class PDFFORQTLIBSHARED_EXPORT PDFCreateHighlightTextTool : public PDFCreateAnnotationTool
{
Q_OBJECT
private:
using BaseClass = PDFCreateAnnotationTool;
public:
/// Creates new highlight text tool
/// \param proxy Proxy
/// \param type Annotation type, must be one of: Highlight, Underline, Squiggly, StrikeOut
/// \param action Action
/// \param parent Parent
explicit PDFCreateHighlightTextTool(PDFDrawWidgetProxy* proxy, PDFToolManager* toolManager, AnnotationType type, QAction* action, QObject* parent);
virtual void drawPage(QPainter* painter,
PDFInteger pageIndex,
const PDFPrecompiledPage* compiledPage,
PDFTextLayoutGetter& layoutGetter,
const QMatrix& pagePointToDevicePointMatrix,
QList<PDFRenderError>& errors) const override;
virtual void mousePressEvent(QWidget* widget, QMouseEvent* event) override;
virtual void mouseReleaseEvent(QWidget* widget, QMouseEvent* event) override;
virtual void mouseMoveEvent(QWidget* widget, QMouseEvent* event) override;
protected:
virtual void setActiveImpl(bool active) override;
private:
void updateCursor();
void setSelection(pdf::PDFTextSelection&& textSelection);
struct SelectionInfo
{
PDFInteger pageIndex = -1;
QPointF selectionStartPoint;
};
PDFToolManager* m_toolManager;
AnnotationType m_type;
pdf::PDFTextSelection m_textSelection;
SelectionInfo m_selectionInfo;
bool m_isCursorOverText;
};
} // namespace pdf
#endif // PDFADVANCEDTOOLS_H

View File

@ -236,7 +236,8 @@ void PDFTextLayoutGenerator::performOutputCharacter(const PDFTextCharacterInfo&
PDFAsynchronousTextLayoutCompiler::PDFAsynchronousTextLayoutCompiler(PDFDrawWidgetProxy* proxy) :
BaseClass(proxy),
m_proxy(proxy),
m_isRunning(false)
m_isRunning(false),
m_cache(std::bind(&PDFAsynchronousTextLayoutCompiler::createTextLayout, this, std::placeholders::_1))
{
connect(&m_textLayoutCompileFutureWatcher, &QFutureWatcher<PDFTextLayoutStorage>::finished, this, &PDFAsynchronousTextLayoutCompiler::onTextLayoutCreated);
}
@ -279,6 +280,7 @@ void PDFAsynchronousTextLayoutCompiler::stop(bool clearCache)
if (clearCache)
{
m_textLayouts = std::nullopt;
m_cache.clear();
}
m_state = State::Inactive;
@ -300,6 +302,50 @@ void PDFAsynchronousTextLayoutCompiler::reset()
start();
}
PDFTextLayout PDFAsynchronousTextLayoutCompiler::createTextLayout(PDFInteger pageIndex)
{
PDFTextLayout result;
if (isTextLayoutReady())
{
result = getTextLayout(pageIndex);
}
else
{
if (m_state != State::Active || !m_proxy->getDocument())
{
// Engine is not active, do not calculate layout
return result;
}
const PDFCatalog* catalog = m_proxy->getDocument()->getCatalog();
if (pageIndex < 0 || pageIndex >= PDFInteger(catalog->getPageCount()))
{
return result;
}
if (!catalog->getPage(pageIndex))
{
// Invalid page index
return result;
}
const PDFPage* page = catalog->getPage(pageIndex);
Q_ASSERT(page);
bool guard = false;
m_proxy->getFontCache()->setCacheShrinkEnabled(&guard, false);
PDFCMSPointer cms = m_proxy->getCMSManager()->getCurrentCMS();
PDFTextLayoutGenerator generator(m_proxy->getFeatures(), page, m_proxy->getDocument(), m_proxy->getFontCache(), cms.data(), m_proxy->getOptionalContentActivity(), QMatrix(), m_proxy->getMeshQualitySettings());
generator.processContents();
result = generator.createTextLayout();
m_proxy->getFontCache()->setCacheShrinkEnabled(&guard, true);
}
return result;
}
PDFTextLayout PDFAsynchronousTextLayoutCompiler::getTextLayout(PDFInteger pageIndex)
{
if (m_state != State::Active || !m_proxy->getDocument())
@ -318,18 +364,7 @@ PDFTextLayout PDFAsynchronousTextLayoutCompiler::getTextLayout(PDFInteger pageIn
PDFTextLayoutGetter PDFAsynchronousTextLayoutCompiler::getTextLayoutLazy(PDFInteger pageIndex)
{
if (m_state != State::Active || !m_proxy->getDocument())
{
// Engine is not active, always return empty layout
return PDFTextLayoutGetter(nullptr, pageIndex);
}
if (m_textLayouts)
{
return m_textLayouts->getTextLayoutLazy(pageIndex);
}
return PDFTextLayoutGetter(nullptr, pageIndex);
return PDFTextLayoutGetter(&m_cache, pageIndex);
}
PDFTextSelection PDFAsynchronousTextLayoutCompiler::getTextSelectionAll(QColor color) const
@ -454,6 +489,7 @@ void PDFAsynchronousTextLayoutCompiler::onTextLayoutCreated()
{
m_proxy->getFontCache()->setCacheShrinkEnabled(this, true);
m_proxy->getProgress()->finish();
m_cache.clear();
m_textLayouts = m_textLayoutCompileFuture.result();
m_isRunning = false;

View File

@ -129,6 +129,12 @@ public:
Stopping
};
/// Creates text layout of the page synchronously. If page index is invalid,
/// then empty text layout is returned. Compiler must be active to get
/// valid text layout.
/// \param pageIndex Page index
PDFTextLayout createTextLayout(PDFInteger pageIndex);
/// Returns text layout of the page. If page index is invalid,
/// then empty text layout is returned.
/// \param pageIndex Page index
@ -166,6 +172,7 @@ private:
std::optional<PDFTextLayoutStorage> m_textLayouts;
QFuture<PDFTextLayoutStorage> m_textLayoutCompileFuture;
QFutureWatcher<PDFTextLayoutStorage> m_textLayoutCompileFutureWatcher;
PDFTextLayoutCache m_cache;
};
class PDFTextLayoutGenerator : public PDFPageContentProcessor

View File

@ -1306,7 +1306,7 @@ bool PDFFindResult::operator<(const PDFFindResult& other) const
return textSelectionItems.front() < other.textSelectionItems.front();
}
PDFTextLayout PDFTextLayoutGetter::getTextLayoutImpl() const
PDFTextLayout PDFTextLayoutStorageGetter::getTextLayoutImpl() const
{
return m_storage ? m_storage->getTextLayout(m_pageIndex) : PDFTextLayout();
}
@ -1423,4 +1423,29 @@ void PDFTextSelectionPainter::draw(QPainter* painter, PDFInteger pageIndex, PDFT
painter->restore();
}
PDFTextLayoutCache::PDFTextLayoutCache(std::function<PDFTextLayout (PDFInteger)> textLayoutGetter) :
m_textLayoutGetter(qMove(textLayoutGetter)),
m_pageIndex(-1),
m_layout()
{
}
void PDFTextLayoutCache::clear()
{
m_pageIndex = -1;
m_layout = PDFTextLayout();
}
const PDFTextLayout& PDFTextLayoutCache::getTextLayout(PDFInteger pageIndex)
{
if (m_pageIndex != pageIndex)
{
m_pageIndex = pageIndex;
m_layout = m_textLayoutGetter(pageIndex);
}
return m_layout;
}
} // namespace pdf

View File

@ -395,13 +395,55 @@ private:
PDFTextBlocks m_blocks;
};
/// Cache for storing single text layout
class PDFFORQTLIBSHARED_EXPORT PDFTextLayoutCache
{
public:
explicit PDFTextLayoutCache(std::function<PDFTextLayout(PDFInteger)> textLayoutGetter);
/// Clears the cache
void clear();
/// Returns text layout. This function always succeeds. If compiler is not active,
/// then empty layout is returned.
/// \param compiler Text layout compiler
/// \param pageIndex Page index
const PDFTextLayout& getTextLayout(PDFInteger pageIndex);
private:
std::function<PDFTextLayout(PDFInteger)> m_textLayoutGetter;
PDFInteger m_pageIndex;
PDFTextLayout m_layout;
};
class PDFFORQTLIBSHARED_EXPORT PDFTextLayoutGetter
{
public:
explicit inline PDFTextLayoutGetter(PDFTextLayoutCache* cache, PDFInteger pageIndex) :
m_cache(cache),
m_pageIndex(pageIndex)
{
}
/// Cast operator, casts to constant reference to PDFTextLayout
operator const PDFTextLayout&()
{
return m_cache->getTextLayout(m_pageIndex);
}
private:
PDFTextLayoutCache* m_cache;
PDFInteger m_pageIndex;
};
/// Lazy getter for text layouts from storage. This is used, when we do not want to
/// get text layout each time, because it is time expensive. If text layout is not needed,
/// then nothing happens. Text layout is returned only, if conversion operator is used.
class PDFTextLayoutGetter
class PDFTextLayoutStorageGetter
{
public:
explicit PDFTextLayoutGetter(const PDFTextLayoutStorage* storage, PDFInteger pageIndex) :
explicit PDFTextLayoutStorageGetter(const PDFTextLayoutStorage* storage, PDFInteger pageIndex) :
m_storage(storage),
m_pageIndex(pageIndex)
{
@ -411,7 +453,7 @@ public:
/// Cast operator, casts to constant reference to PDFTextLayout
operator const PDFTextLayout&()
{
return m_textLayout.get(this, &PDFTextLayoutGetter::getTextLayoutImpl);
return m_textLayout.get(this, &PDFTextLayoutStorageGetter::getTextLayoutImpl);
}
private:
@ -471,7 +513,7 @@ public:
/// then empty text layout is returned. Function is not thread safe, if
/// function \p setTextLayout is called from another thread.
/// \param pageIndex Page index
PDFTextLayoutGetter getTextLayoutLazy(PDFInteger pageIndex) const { return PDFTextLayoutGetter(this, pageIndex); }
PDFTextLayoutStorageGetter getTextLayoutLazy(PDFInteger pageIndex) const { return PDFTextLayoutStorageGetter(this, pageIndex); }
/// Sets text layout to the particular index. Index must be valid and from
/// range 0 to \p pageCount - 1. Function is not thread safe.

View File

@ -53,5 +53,9 @@
<file>resources/signature.svg</file>
<file>resources/plugins.svg</file>
<file>resources/hyperlink.svg</file>
<file>resources/highlight.svg</file>
<file>resources/squiggly.svg</file>
<file>resources/strikeout.svg</file>
<file>resources/underline.svg</file>
</qresource>
</RCC>

View File

@ -369,6 +369,14 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
m_toolManager->addTool(createFreehandCurveTool);
pdf::PDFCreateStampTool* createStampTool = new pdf::PDFCreateStampTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, m_insertStampGroup, this);
m_toolManager->addTool(createStampTool);
pdf::PDFCreateHighlightTextTool* createHighlightTextTool = new pdf::PDFCreateHighlightTextTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, pdf::AnnotationType::Highlight, ui->actionCreateTextHighlight, this);
m_toolManager->addTool(createHighlightTextTool);
pdf::PDFCreateHighlightTextTool* createUnderlineTextTool = new pdf::PDFCreateHighlightTextTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, pdf::AnnotationType::Underline, ui->actionCreateTextUnderline, this);
m_toolManager->addTool(createUnderlineTextTool);
pdf::PDFCreateHighlightTextTool* createStrikeOutTextTool = new pdf::PDFCreateHighlightTextTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, pdf::AnnotationType::StrikeOut, ui->actionCreateTextStrikeout, this);
m_toolManager->addTool(createStrikeOutTextTool);
pdf::PDFCreateHighlightTextTool* createSquigglyTextTool = new pdf::PDFCreateHighlightTextTool(m_pdfWidget->getDrawWidgetProxy(), m_toolManager, pdf::AnnotationType::Squiggly, ui->actionCreateTextSquiggly, this);
m_toolManager->addTool(createSquigglyTextTool);
m_annotationManager = new pdf::PDFWidgetAnnotationManager(m_pdfWidget->getDrawWidgetProxy(), this);
connect(m_annotationManager, &pdf::PDFWidgetAnnotationManager::actionTriggered, this, &PDFViewerMainWindow::onActionTriggered);
@ -479,6 +487,11 @@ void PDFViewerMainWindow::loadPlugins()
{
for (QAction* action : toolbarButton->menu()->actions())
{
if (action->isSeparator())
{
continue;
}
if (action->isEnabled())
{
toolbarButton->setDefaultAction(action);

View File

@ -151,6 +151,15 @@
<string>Stamp</string>
</property>
</widget>
<widget class="QMenu" name="menuTextHighlight">
<property name="title">
<string>Text Higlight</string>
</property>
<addaction name="actionCreateTextHighlight"/>
<addaction name="actionCreateTextUnderline"/>
<addaction name="actionCreateTextStrikeout"/>
<addaction name="actionCreateTextSquiggly"/>
</widget>
<addaction name="menuSticky_Note"/>
<addaction name="actionCreateHyperlink"/>
<addaction name="actionInlineText"/>
@ -160,6 +169,7 @@
<addaction name="actionCreateEllipse"/>
<addaction name="actionCreateFreehandCurve"/>
<addaction name="menuStamp"/>
<addaction name="menuTextHighlight"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
@ -697,6 +707,54 @@
<string>Freehand Curve</string>
</property>
</action>
<action name="actionCreateTextHighlight">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/highlight.svg</normaloff>:/resources/highlight.svg</iconset>
</property>
<property name="text">
<string>Highlight</string>
</property>
</action>
<action name="actionCreateTextUnderline">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/underline.svg</normaloff>:/resources/underline.svg</iconset>
</property>
<property name="text">
<string>Underline</string>
</property>
</action>
<action name="actionCreateTextStrikeout">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/strikeout.svg</normaloff>:/resources/strikeout.svg</iconset>
</property>
<property name="text">
<string>Strikeout</string>
</property>
</action>
<action name="actionCreateTextSquiggly">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/squiggly.svg</normaloff>:/resources/squiggly.svg</iconset>
</property>
<property name="text">
<string>Squiggly</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="highlight.svg">
<defs
id="defs5285">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 15 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="30 : 15 : 1"
inkscape:persp3d-origin="15 : 10 : 1"
id="perspective5921" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.9999996"
inkscape:cx="51.633241"
inkscape:cy="75.073314"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<g
aria-label="ab"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text972">
<path
d="M 12.265918,291.11298 H 9.9466794 v -1.47588 q -0.3100586,0.21084 -0.8433593,0.59531 -0.5208985,0.37207 -1.0169922,0.59531 -0.5829102,0.28526 -1.3394531,0.47129 -0.756543,0.19844 -1.7735352,0.19844 -1.8727538,0 -3.1749999,-1.24024 -1.30224608,-1.24023 -1.30224608,-3.16259 0,-1.5751 0.66972658,-2.54248 0.6821289,-0.97979 1.9347656,-1.53789 1.265039,-0.55811 3.0385741,-0.75655 1.7735352,-0.19843 3.8075195,-0.29765 v -0.35967 q 0,-0.79375 -0.2852539,-1.31465 -0.2728515,-0.5209 -0.79375,-0.81855 -0.4960937,-0.28526 -1.190625,-0.38448 -0.6945312,-0.0992 -1.4510742,-0.0992 -0.9177734,0 -2.0463866,0.24805 -1.1286133,0.23565 -2.3316406,0.69453 H 1.7239256 v -2.36885 q 0.6821289,-0.18603 1.9719727,-0.40927 1.2898437,-0.22324 2.5424804,-0.22324 1.4634765,0 2.5424804,0.24804 1.0914063,0.23565 1.8851559,0.81856 0.781348,0.5705 1.190625,1.47588 0.409278,0.90537 0.409278,2.24482 z m -2.3192386,-3.41065 v -3.85713 q -1.0666015,0.062 -2.5176757,0.18604 -1.4386719,0.12402 -2.2820312,0.35967 -1.0045899,0.28525 -1.624707,0.89296 -0.6201172,0.59532 -0.6201172,1.64952 0,1.19062 0.7193359,1.79834 0.7193359,0.59531 2.1952148,0.59531 1.227832,0 2.2448242,-0.47129 1.0169922,-0.48369 1.8851562,-1.15342 z"
style="stroke-width:0.26458332"
id="path2227"
inkscape:connector-curvature="0" />
<path
d="m 28.971874,284.08085 q 0,1.73633 -0.496094,3.12539 -0.483691,1.38906 -1.314648,2.33164 -0.880566,0.97978 -1.934766,1.47588 -1.054199,0.48369 -2.319238,0.48369 -1.178223,0 -2.058789,-0.28526 -0.880566,-0.27285 -1.736328,-0.74414 l -0.148828,0.64493 H 16.78037 v -19.29805 h 2.331641 v 6.8957 q 0.979785,-0.80615 2.083594,-1.31465 1.103808,-0.52089 2.480468,-0.52089 2.455664,0 3.869532,1.88515 1.426269,1.88516 1.426269,5.32061 z m -2.406055,0.062 q 0,-2.48047 -0.818554,-3.75791 -0.818555,-1.28984 -2.641699,-1.28984 -1.016993,0 -2.058789,0.44648 -1.041797,0.43408 -1.934766,1.12861 v 7.9375 q 0.992187,0.44649 1.699121,0.62012 0.719336,0.17363 1.624707,0.17363 1.934766,0 3.026172,-1.26504 1.103808,-1.27744 1.103808,-3.99355 z"
style="stroke-width:0.26458332"
id="path2229"
inkscape:connector-curvature="0" />
</g>
<rect
style="opacity:1;fill:#ffff00;fill-opacity:0.25490198;stroke:none;stroke-width:1.89999998;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect2232"
width="28.442711"
height="19.744532"
x="0.52916664"
y="271.76535" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="squiggly.svg">
<defs
id="defs5285">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 15 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="30 : 15 : 1"
inkscape:persp3d-origin="15 : 10 : 1"
id="perspective5921" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="89.028194"
inkscape:cy="37.937149"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
x="-0.79375011"
y="291.11298"
id="text972"><tspan
sodipodi:role="line"
id="tspan970"
x="-0.79375011"
y="291.11298"
style="stroke-width:0.26458332">ab</tspan></text>
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.4221355,293.99037 1.5213542,-1.55443 1.3890626,1.52135"
id="path2905"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 4.3325523,293.95729 1.5213542,-1.55443 1.3890626,1.52135"
id="path2905-8"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 7.2429691,293.92421 1.5213542,-1.55443 1.3890627,1.52135"
id="path2905-8-3"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.153386,293.89113 1.521354,-1.55443 1.389063,1.52135"
id="path2905-8-5"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.063803,293.85805 1.521354,-1.55443 1.389063,1.52135"
id="path2905-8-2"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 15.97422,293.82497 1.521354,-1.55443 1.389062,1.52135"
id="path2905-8-0"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 18.884636,293.79189 1.521354,-1.55443 1.389063,1.52135"
id="path2905-8-29"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 21.795053,293.75881 1.521355,-1.55443 1.389062,1.52135"
id="path2905-8-6"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ff0000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 24.70547,293.72573 1.521354,-1.55443 1.389062,1.52135"
id="path2905-8-7"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="strikeout.svg">
<defs
id="defs5285">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 15 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="30 : 15 : 1"
inkscape:persp3d-origin="15 : 10 : 1"
id="perspective5921" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.9999998"
inkscape:cx="253.27643"
inkscape:cy="-27.618099"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<g
aria-label="ab"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text972">
<path
d="M 12.265918,291.11298 H 9.9466794 v -1.47588 q -0.3100586,0.21084 -0.8433593,0.59531 -0.5208985,0.37207 -1.0169922,0.59531 -0.5829102,0.28526 -1.3394531,0.47129 -0.756543,0.19844 -1.7735352,0.19844 -1.8727538,0 -3.1749999,-1.24024 -1.30224608,-1.24023 -1.30224608,-3.16259 0,-1.5751 0.66972658,-2.54248 0.6821289,-0.97979 1.9347656,-1.53789 1.265039,-0.55811 3.0385741,-0.75655 1.7735352,-0.19843 3.8075195,-0.29765 v -0.35967 q 0,-0.79375 -0.2852539,-1.31465 -0.2728515,-0.5209 -0.79375,-0.81855 -0.4960937,-0.28526 -1.190625,-0.38448 -0.6945312,-0.0992 -1.4510742,-0.0992 -0.9177734,0 -2.0463866,0.24805 -1.1286133,0.23565 -2.3316406,0.69453 H 1.7239256 v -2.36885 q 0.6821289,-0.18603 1.9719727,-0.40927 1.2898437,-0.22324 2.5424804,-0.22324 1.4634765,0 2.5424804,0.24804 1.0914063,0.23565 1.8851559,0.81856 0.781348,0.5705 1.190625,1.47588 0.409278,0.90537 0.409278,2.24482 z m -2.3192386,-3.41065 v -3.85713 q -1.0666015,0.062 -2.5176757,0.18604 -1.4386719,0.12402 -2.2820312,0.35967 -1.0045899,0.28525 -1.624707,0.89296 -0.6201172,0.59532 -0.6201172,1.64952 0,1.19062 0.7193359,1.79834 0.7193359,0.59531 2.1952148,0.59531 1.227832,0 2.2448242,-0.47129 1.0169922,-0.48369 1.8851562,-1.15342 z"
style="stroke-width:0.26458332"
id="path974"
inkscape:connector-curvature="0" />
<path
d="m 28.971874,284.08085 q 0,1.73633 -0.496094,3.12539 -0.483691,1.38906 -1.314648,2.33164 -0.880566,0.97978 -1.934766,1.47588 -1.054199,0.48369 -2.319238,0.48369 -1.178223,0 -2.058789,-0.28526 -0.880566,-0.27285 -1.736328,-0.74414 l -0.148828,0.64493 H 16.78037 v -19.29805 h 2.331641 v 6.8957 q 0.979785,-0.80615 2.083594,-1.31465 1.103808,-0.52089 2.480468,-0.52089 2.455664,0 3.869532,1.88515 1.426269,1.88516 1.426269,5.32061 z m -2.406055,0.062 q 0,-2.48047 -0.818554,-3.75791 -0.818555,-1.28984 -2.641699,-1.28984 -1.016993,0 -2.058789,0.44648 -1.041797,0.43408 -1.934766,1.12861 v 7.9375 q 0.992187,0.44649 1.699121,0.62012 0.719336,0.17363 1.624707,0.17363 1.934766,0 3.026172,-1.26504 1.103808,-1.27744 1.103808,-3.99355 z"
style="stroke-width:0.26458332"
id="path976"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:none;stroke:#ff0000;stroke-width:1.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.5622396,284.10158 28.905731,283.96929"
id="path979"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="underline.svg">
<defs
id="defs5285">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 15 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="30 : 15 : 1"
inkscape:persp3d-origin="15 : 10 : 1"
id="perspective5921" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.9999996"
inkscape:cx="51.633241"
inkscape:cy="75.073314"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<g
aria-label="ab"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text972">
<path
d="M 12.265918,291.11298 H 9.9466794 v -1.47588 q -0.3100586,0.21084 -0.8433593,0.59531 -0.5208985,0.37207 -1.0169922,0.59531 -0.5829102,0.28526 -1.3394531,0.47129 -0.756543,0.19844 -1.7735352,0.19844 -1.8727538,0 -3.1749999,-1.24024 -1.30224608,-1.24023 -1.30224608,-3.16259 0,-1.5751 0.66972658,-2.54248 0.6821289,-0.97979 1.9347656,-1.53789 1.265039,-0.55811 3.0385741,-0.75655 1.7735352,-0.19843 3.8075195,-0.29765 v -0.35967 q 0,-0.79375 -0.2852539,-1.31465 -0.2728515,-0.5209 -0.79375,-0.81855 -0.4960937,-0.28526 -1.190625,-0.38448 -0.6945312,-0.0992 -1.4510742,-0.0992 -0.9177734,0 -2.0463866,0.24805 -1.1286133,0.23565 -2.3316406,0.69453 H 1.7239256 v -2.36885 q 0.6821289,-0.18603 1.9719727,-0.40927 1.2898437,-0.22324 2.5424804,-0.22324 1.4634765,0 2.5424804,0.24804 1.0914063,0.23565 1.8851559,0.81856 0.781348,0.5705 1.190625,1.47588 0.409278,0.90537 0.409278,2.24482 z m -2.3192386,-3.41065 v -3.85713 q -1.0666015,0.062 -2.5176757,0.18604 -1.4386719,0.12402 -2.2820312,0.35967 -1.0045899,0.28525 -1.624707,0.89296 -0.6201172,0.59532 -0.6201172,1.64952 0,1.19062 0.7193359,1.79834 0.7193359,0.59531 2.1952148,0.59531 1.227832,0 2.2448242,-0.47129 1.0169922,-0.48369 1.8851562,-1.15342 z"
style="stroke-width:0.26458332"
id="path1651"
inkscape:connector-curvature="0" />
<path
d="m 28.971874,284.08085 q 0,1.73633 -0.496094,3.12539 -0.483691,1.38906 -1.314648,2.33164 -0.880566,0.97978 -1.934766,1.47588 -1.054199,0.48369 -2.319238,0.48369 -1.178223,0 -2.058789,-0.28526 -0.880566,-0.27285 -1.736328,-0.74414 l -0.148828,0.64493 H 16.78037 v -19.29805 h 2.331641 v 6.8957 q 0.979785,-0.80615 2.083594,-1.31465 1.103808,-0.52089 2.480468,-0.52089 2.455664,0 3.869532,1.88515 1.426269,1.88516 1.426269,5.32061 z m -2.406055,0.062 q 0,-2.48047 -0.818554,-3.75791 -0.818555,-1.28984 -2.641699,-1.28984 -1.016993,0 -2.058789,0.44648 -1.041797,0.43408 -1.934766,1.12861 v 7.9375 q 0.992187,0.44649 1.699121,0.62012 0.719336,0.17363 1.624707,0.17363 1.934766,0 3.026172,-1.26504 1.103808,-1.27744 1.103808,-3.99355 z"
style="stroke-width:0.26458332"
id="path1653"
inkscape:connector-curvature="0" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 0.66145835,293.29584 29.137242,293.16354"
id="path1656"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB