Skip to content

Commit

Permalink
More fixes for use of inline data for SVG content
Browse files Browse the repository at this point in the history
Followup #59589

Fixes #60427
  • Loading branch information
nyalldawson committed Feb 5, 2025
1 parent 997a591 commit 0287956
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
try:
QgsAbstractContentCacheBase.__attribute_docs__ = {'remoteContentFetched': 'Emitted when the cache has finished retrieving content from a remote ``url``.\n'}
QgsAbstractContentCacheBase.parseBase64DataUrl = staticmethod(QgsAbstractContentCacheBase.parseBase64DataUrl)
QgsAbstractContentCacheBase.parseEmbeddedStringData = staticmethod(QgsAbstractContentCacheBase.parseEmbeddedStringData)
QgsAbstractContentCacheBase.isBase64Data = staticmethod(QgsAbstractContentCacheBase.isBase64Data)
QgsAbstractContentCacheBase.__signal_arguments__ = {'remoteContentFetched': ['url: str']}
except (NameError, AttributeError):
Expand Down
17 changes: 17 additions & 0 deletions python/PyQt6/core/auto_generated/qgsabstractcontentcache.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ Data URLs are of the form ``data:[<mediatype>;]base64,<data>``.
.. versionadded:: 3.40
%End


static bool parseEmbeddedStringData( const QString &path, QString *mimeType /Out/ = 0, QString *data /Out/ = 0 );
%Docstring
Parses a ``path`` to determine if it represents a embedded string data, and if so, extracts the components
of the URL.

Data URLs are of the form ``data:[<mediatype>;]utf8,<data>``.

:param path: path to test

:return: - ``True`` if ``path`` is an embedded string data URL
- mimeType: the extracted mime type if the ``path`` is a data URL
- data: the extracted string data if the ``path`` is a data URL

.. versionadded:: 3.42
%End

static bool isBase64Data( const QString &path );
%Docstring
Returns ``True`` if ``path`` represents base64 encoded data.
Expand Down
1 change: 1 addition & 0 deletions python/core/auto_additions/qgsabstractcontentcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
try:
QgsAbstractContentCacheBase.__attribute_docs__ = {'remoteContentFetched': 'Emitted when the cache has finished retrieving content from a remote ``url``.\n'}
QgsAbstractContentCacheBase.parseBase64DataUrl = staticmethod(QgsAbstractContentCacheBase.parseBase64DataUrl)
QgsAbstractContentCacheBase.parseEmbeddedStringData = staticmethod(QgsAbstractContentCacheBase.parseEmbeddedStringData)
QgsAbstractContentCacheBase.isBase64Data = staticmethod(QgsAbstractContentCacheBase.isBase64Data)
QgsAbstractContentCacheBase.__signal_arguments__ = {'remoteContentFetched': ['url: str']}
except (NameError, AttributeError):
Expand Down
17 changes: 17 additions & 0 deletions python/core/auto_generated/qgsabstractcontentcache.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ Data URLs are of the form ``data:[<mediatype>;]base64,<data>``.
.. versionadded:: 3.40
%End


static bool parseEmbeddedStringData( const QString &path, QString *mimeType /Out/ = 0, QString *data /Out/ = 0 );
%Docstring
Parses a ``path`` to determine if it represents a embedded string data, and if so, extracts the components
of the URL.

Data URLs are of the form ``data:[<mediatype>;]utf8,<data>``.

:param path: path to test

:return: - ``True`` if ``path`` is an embedded string data URL
- mimeType: the extracted mime type if the ``path`` is a data URL
- data: the extracted string data if the ``path`` is a data URL

.. versionadded:: 3.42
%End

static bool isBase64Data( const QString &path );
%Docstring
Returns ``True`` if ``path`` represents base64 encoded data.
Expand Down
16 changes: 16 additions & 0 deletions src/core/qgsabstractcontentcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ bool QgsAbstractContentCacheBase::parseBase64DataUrl( const QString &path, QStri
return true;
}

bool QgsAbstractContentCacheBase::parseEmbeddedStringData( const QString &path, QString *mimeType, QString *data )
{
const thread_local QRegularExpression sRx( QStringLiteral( "^data:([a-zA-Z0-9+\\-]*\\/[a-zA-Z0-9+\\-]*?)\\;utf8,(.*)$" ), QRegularExpression::DotMatchesEverythingOption );
const QRegularExpressionMatch stringMatch = sRx.match( path );

if ( !stringMatch.hasMatch() )
return false;

if ( mimeType )
*mimeType = stringMatch.captured( 1 );
if ( data )
*data = stringMatch.captured( 2 );

return true;
}

bool QgsAbstractContentCacheBase::isBase64Data( const QString &path )
{
return path.startsWith( QLatin1String( "base64:" ) )
Expand Down
17 changes: 17 additions & 0 deletions src/core/qgsabstractcontentcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,23 @@ class CORE_EXPORT QgsAbstractContentCacheBase: public QObject
*/
static bool parseBase64DataUrl( const QString &path, QString *mimeType SIP_OUT = nullptr, QString *data SIP_OUT = nullptr );


/**
* Parses a \a path to determine if it represents a embedded string data, and if so, extracts the components
* of the URL.
*
* Data URLs are of the form ``data:[<mediatype>;]utf8,<data>``.
*
* \param path path to test
* \param mimeType will be set to the extracted mime type if the \a path is a data URL
* \param data will be set to the extracted string data if the \a path is a data URL
*
* \returns TRUE if \a path is an embedded string data URL
*
* \since QGIS 3.42
*/
static bool parseEmbeddedStringData( const QString &path, QString *mimeType SIP_OUT = nullptr, QString *data SIP_OUT = nullptr );

/**
* Returns TRUE if \a path represents base64 encoded data.
*
Expand Down
6 changes: 6 additions & 0 deletions src/core/qgsabstractcontentcache_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ QByteArray QgsAbstractContentCache<T>::getContent( const QString &path, const QB
{
return QByteArray::fromBase64( base64String.toLocal8Bit(), QByteArray::OmitTrailingEquals );
}
// maybe embedded string data
QString embeddedString;
if ( parseEmbeddedStringData( path, nullptr, &embeddedString ) )
{
return embeddedString.toUtf8();
}
}

// maybe it's a url...
Expand Down
1 change: 1 addition & 0 deletions tests/src/core/testqgssvgcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,5 +433,6 @@ bool TestQgsSvgCache::imageCheck( const QString &testName, QImage &image, int mi
mReport += checker.report();
return resultFlag;
}

QGSTEST_MAIN( TestQgsSvgCache )
#include "testqgssvgcache.moc"
23 changes: 23 additions & 0 deletions tests/src/python/test_qgssvgcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,29 @@ def test_inline_svg(self):
)
)

def test_inline_svg_no_block(self):
# note, this is different content to test_inline_svg, we don't want to retrieve a cached version!
inline_svg = """data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_2" x="0px" y="0px" viewBox="0 0 100 100" xml:space="preserve" height="100px" width="100px"><path fill="#000000" d="M50,2.5c-19.2,0-34.8,15-34.8,33.4C15.2,61.3,50,97.5,50,97.5s34.8-36.2,34.8-61.6 C84.8,17.5,69.2,2.5,50,2.5z M50,48.2c-7.1,0-12.9-5.8-12.9-12.9c0-7.1,5.8-12.9,12.9-12.9c7.1,0,12.9,5.8,12.9,12.9 C62.9,42.4,57.1,48.2,50,48.2z"/></svg>"""
image, in_cache = QgsApplication.svgCache().svgAsImage(
inline_svg,
100,
fill=QColor(0, 0, 0),
stroke=QColor(0, 0, 0),
strokeWidth=0.1,
widthScaleFactor=1,
blocking=False,
)
self.assertTrue(
self.image_check(
"Inline svg",
"inline_svg",
image,
color_tolerance=2,
allowed_mismatch=20,
use_checkerboard_background=True,
)
)


if __name__ == "__main__":
unittest.main()

0 comments on commit 0287956

Please sign in to comment.