Skip to content

Commit

Permalink
Allow QgsTextFragment to represent an inline image object
Browse files Browse the repository at this point in the history
Modifies the QgsTextDocument API to extract images from HTML
content, and store in the associated
QgsTextFragment/QgsTextCharacterFormat objects
  • Loading branch information
nyalldawson committed Sep 16, 2024
1 parent 84b1004 commit edcd18f
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,62 @@ Returns whether the format has overline enabled.
Sets whether the format has overline ``enabled``.

.. seealso:: :py:func:`overline`
%End

QString imagePath() const;
%Docstring
Returns the path to the image to render, if the format applies to a document image fragment.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`imageSize`

.. seealso:: :py:func:`setImagePath`

.. versionadded:: 3.40
%End

void setImagePath( const QString &path );
%Docstring
Sets the ``path`` to the image to render, if the format applies to a document image fragment.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`setImageSize`

.. seealso:: :py:func:`imagePath`

.. versionadded:: 3.40
%End

QSizeF imageSize() const;
%Docstring
Returns the image size, if the format applies to a document image fragment.

The image size is always considered to be in :py:class:`Qgis`.RenderUnit.Points.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`imagePath`

.. seealso:: :py:func:`setImageSize`

.. versionadded:: 3.40
%End

void setImageSize( const QSizeF &size );
%Docstring
Sets the image ``size``, if the format applies to a document image fragment.

The image size is always considered to be in :py:class:`Qgis`.RenderUnit.Points.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`setImagePath`

.. seealso:: :py:func:`imageSize`

.. versionadded:: 3.40
%End

bool hasVerticalAlignmentSet() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
class QgsTextFragment
{
%Docstring(signature="appended")
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
Stores a fragment of document along with formatting overrides to be used when rendering the fragment.

Text fragments consist of either a block of text or another atomic component of a document (such as an image).

Each fragment has an associated :py:func:`~characterFormat`, which specifies the text formatting overrides
to use when rendering the fragment. Additionally, the :py:func:`~characterFormat` may contain properties
for other fragment types, such as image paths and sizes for image fragments.

.. warning::

Expand Down Expand Up @@ -77,6 +83,13 @@ Returns the character formatting for the fragment.
Sets the character ``format`` for the fragment.

.. seealso:: :py:func:`characterFormat`
%End

bool isImage() const;
%Docstring
Returns ``True`` if the fragment represents an image.

.. versionadded:: 3.40
%End

double horizontalAdvance( const QFont &font, const QgsRenderContext &context, bool fontHasBeenUpdatedForFragment = false, double scaleFactor = 1.0 ) const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,62 @@ Returns whether the format has overline enabled.
Sets whether the format has overline ``enabled``.

.. seealso:: :py:func:`overline`
%End

QString imagePath() const;
%Docstring
Returns the path to the image to render, if the format applies to a document image fragment.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`imageSize`

.. seealso:: :py:func:`setImagePath`

.. versionadded:: 3.40
%End

void setImagePath( const QString &path );
%Docstring
Sets the ``path`` to the image to render, if the format applies to a document image fragment.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`setImageSize`

.. seealso:: :py:func:`imagePath`

.. versionadded:: 3.40
%End

QSizeF imageSize() const;
%Docstring
Returns the image size, if the format applies to a document image fragment.

The image size is always considered to be in :py:class:`Qgis`.RenderUnit.Points.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`imagePath`

.. seealso:: :py:func:`setImageSize`

.. versionadded:: 3.40
%End

void setImageSize( const QSizeF &size );
%Docstring
Sets the image ``size``, if the format applies to a document image fragment.

The image size is always considered to be in :py:class:`Qgis`.RenderUnit.Points.

.. seealso:: :py:func:`QgsTextFragment.isImage`

.. seealso:: :py:func:`setImagePath`

.. seealso:: :py:func:`imageSize`

.. versionadded:: 3.40
%End

bool hasVerticalAlignmentSet() const;
Expand Down
15 changes: 14 additions & 1 deletion python/core/auto_generated/textrenderer/qgstextfragment.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
class QgsTextFragment
{
%Docstring(signature="appended")
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
Stores a fragment of document along with formatting overrides to be used when rendering the fragment.

Text fragments consist of either a block of text or another atomic component of a document (such as an image).

Each fragment has an associated :py:func:`~characterFormat`, which specifies the text formatting overrides
to use when rendering the fragment. Additionally, the :py:func:`~characterFormat` may contain properties
for other fragment types, such as image paths and sizes for image fragments.

.. warning::

Expand Down Expand Up @@ -77,6 +83,13 @@ Returns the character formatting for the fragment.
Sets the character ``format`` for the fragment.

.. seealso:: :py:func:`characterFormat`
%End

bool isImage() const;
%Docstring
Returns ``True`` if the fragment represents an image.

.. versionadded:: 3.40
%End

double horizontalAdvance( const QFont &font, const QgsRenderContext &context, bool fontHasBeenUpdatedForFragment = false, double scaleFactor = 1.0 ) const;
Expand Down
26 changes: 26 additions & 0 deletions src/core/textrenderer/qgstextcharacterformat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ QgsTextCharacterFormat::QgsTextCharacterFormat( const QTextCharFormat &format )
if ( !families.isEmpty() )
mFontFamily = families.at( 0 );
}
if ( format.isImageFormat() )
{
const QTextImageFormat imageFormat = format.toImageFormat();
mImagePath = imageFormat.name();
mImageSize = QSizeF( imageFormat.width(), imageFormat.height() );
}
}

void QgsTextCharacterFormat::overrideWith( const QgsTextCharacterFormat &other )
Expand Down Expand Up @@ -168,6 +174,26 @@ void QgsTextCharacterFormat::setOverline( QgsTextCharacterFormat::BooleanValue e
mOverline = enabled;
}

QString QgsTextCharacterFormat::imagePath() const
{
return mImagePath;
}

void QgsTextCharacterFormat::setImagePath( const QString &path )
{
mImagePath = path;
}

QSizeF QgsTextCharacterFormat::imageSize() const
{
return mImageSize;
}

void QgsTextCharacterFormat::setImageSize( const QSizeF &size )
{
mImageSize = size;
}

void QgsTextCharacterFormat::updateFontForFormat( QFont &font, const QgsRenderContext &context, const double scaleFactor ) const
{
// important -- MUST set family first
Expand Down
52 changes: 52 additions & 0 deletions src/core/textrenderer/qgstextcharacterformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <QFont>
#include <QColor>
#include <QSizeF>

class QTextCharFormat;
class QgsRenderContext;
Expand Down Expand Up @@ -253,6 +254,54 @@ class CORE_EXPORT QgsTextCharacterFormat
*/
void setOverline( BooleanValue enabled );

/**
* Returns the path to the image to render, if the format applies to a document image fragment.
*
* \see QgsTextFragment::isImage()
* \see imageSize()
* \see setImagePath()
*
* \since QGIS 3.40
*/
QString imagePath() const;

/**
* Sets the \a path to the image to render, if the format applies to a document image fragment.
*
* \see QgsTextFragment::isImage()
* \see setImageSize()
* \see imagePath()
*
* \since QGIS 3.40
*/
void setImagePath( const QString &path );

/**
* Returns the image size, if the format applies to a document image fragment.
*
* The image size is always considered to be in Qgis::RenderUnit::Points.
*
* \see QgsTextFragment::isImage()
* \see imagePath()
* \see setImageSize()
*
* \since QGIS 3.40
*/
QSizeF imageSize() const;

/**
* Sets the image \a size, if the format applies to a document image fragment.
*
* The image size is always considered to be in Qgis::RenderUnit::Points.
*
* \see QgsTextFragment::isImage()
* \see setImagePath()
* \see imageSize()
*
* \since QGIS 3.40
*/
void setImageSize( const QSizeF &size );

/**
* Returns TRUE if the format has an explicit vertical alignment set.
*
Expand Down Expand Up @@ -326,6 +375,9 @@ class CORE_EXPORT QgsTextCharacterFormat
bool mHasVerticalAlignSet = false;
Qgis::TextCharacterVerticalAlignment mVerticalAlign = Qgis::TextCharacterVerticalAlignment::Normal;

QString mImagePath;
QSizeF mImageSize;

BooleanValue mStrikethrough = BooleanValue::NotSet;
BooleanValue mUnderline = BooleanValue::NotSet;
BooleanValue mOverline = BooleanValue::NotSet;
Expand Down
14 changes: 10 additions & 4 deletions src/core/textrenderer/qgstextfragment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
#include "qgsstringutils.h"

QgsTextFragment::QgsTextFragment( const QString &text, const QgsTextCharacterFormat &format )
: mText( text )
: mText( text != QStringLiteral( "\ufffc" ) ? text : QString() )
, mIsImage( text == QStringLiteral( "\ufffc" ) )
, mCharFormat( format )
{}

QgsTextFragment::QgsTextFragment( const QTextFragment &fragment )
: mText( fragment.text() )
, mCharFormat( QgsTextCharacterFormat( fragment.charFormat() ) )
: mText( fragment.text() != QStringLiteral( "\ufffc" ) ? fragment.text() : QString() )
, mIsImage( fragment.text() == QStringLiteral( "\ufffc" ) )
, mCharFormat( fragment.charFormat() )
{

}

QString QgsTextFragment::text() const
Expand All @@ -45,6 +46,11 @@ void QgsTextFragment::setCharacterFormat( const QgsTextCharacterFormat &charForm
mCharFormat = charFormat;
}

bool QgsTextFragment::isImage() const
{
return mIsImage;
}

double QgsTextFragment::horizontalAdvance( const QFont &font, const QgsRenderContext &context, bool fontHasBeenUpdatedForFragment, double scaleFactor ) const
{
if ( fontHasBeenUpdatedForFragment )
Expand Down
16 changes: 15 additions & 1 deletion src/core/textrenderer/qgstextfragment.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ class QTextFragment;
/**
* \class QgsTextFragment
* \ingroup core
* \brief Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
* \brief Stores a fragment of document along with formatting overrides to be used when rendering the fragment.
*
* Text fragments consist of either a block of text or another atomic component of a document (such as an image).
*
* Each fragment has an associated characterFormat(), which specifies the text formatting overrides
* to use when rendering the fragment. Additionally, the characterFormat() may contain properties
* for other fragment types, such as image paths and sizes for image fragments.
*
* \warning This API is not considered stable and may change in future QGIS versions.
*
Expand Down Expand Up @@ -89,6 +95,13 @@ class CORE_EXPORT QgsTextFragment
*/
void setCharacterFormat( const QgsTextCharacterFormat &format );

/**
* Returns TRUE if the fragment represents an image.
*
* \since QGIS 3.40
*/
bool isImage() const;

/**
* Returns the horizontal advance associated with this fragment, when rendered using
* the specified base \a font within the specified render \a context.
Expand All @@ -113,6 +126,7 @@ class CORE_EXPORT QgsTextFragment
private:

QString mText;
bool mIsImage = false;
QgsTextCharacterFormat mCharFormat;
};

Expand Down
8 changes: 8 additions & 0 deletions tests/src/python/test_qgstextcharacterformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
__date__ = '12/05/2020'
__copyright__ = 'Copyright 2020, The QGIS Project'

from qgis.PyQt.QtCore import QSizeF
from qgis.PyQt.QtGui import QColor
from qgis.core import (
Qgis,
Expand Down Expand Up @@ -64,6 +65,13 @@ def testGettersSetters(self):
format.setVerticalAlignment(Qgis.TextCharacterVerticalAlignment.SuperScript)
self.assertEqual(format.verticalAlignment(), Qgis.TextCharacterVerticalAlignment.SuperScript)

self.assertFalse(format.imagePath())
self.assertEqual(format.imageSize(), QSizeF())
format.setImagePath('my.jpg')
format.setImageSize(QSizeF(40, 60))
self.assertEqual(format.imagePath(), 'my.jpg')
self.assertEqual(format.imageSize(), QSizeF(40, 60))

def testUpdateFont(self):
context = QgsRenderContext()
font = QgsFontUtils.getStandardTestFont()
Expand Down
Loading

0 comments on commit edcd18f

Please sign in to comment.