Skip to content
Permalink
Browse files

[FEATURE] QgsTextRenderer class for rich text rendering

Moves all the drawing code out of labeling into a new class
which just handles rendering text. This allows other parts
of the code to utilise all the advanced formatting options
that labeling supports, eg rendering text with shadows,
buffers and backgrounds.
  • Loading branch information
nyalldawson committed Oct 24, 2016
1 parent 074ae42 commit 08143475edb5a920523fb0f56ca7ffbb1870d45e
Showing with 2,488 additions and 897 deletions.
  1. +0 −75 python/core/qgspallabeling.sip
  2. +83 −0 python/core/qgstextrenderer.sip
  3. +1 −1 src/app/qgslabelinggui.cpp
  4. +3 −3 src/app/qgslabelpreview.cpp
  5. +0 −516 src/core/qgspallabeling.cpp
  6. +0 −115 src/core/qgspallabeling.h
  7. +947 −0 src/core/qgstextrenderer.cpp
  8. +176 −1 src/core/qgstextrenderer.h
  9. +1 −1 src/core/qgstextrenderer_p.h
  10. +37 −180 src/core/qgsvectorlayerlabelprovider.cpp
  11. +1 −1 src/core/qgsvectorlayerlabelprovider.h
  12. +1,239 −4 tests/src/python/test_qgstextrenderer.py
  13. BIN tests/testdata/control_images/text_renderer/background_disabled/background_disabled.png
  14. BIN tests/testdata/control_images/text_renderer/background_ellipse_pixels/background_ellipse_pixels.png
  15. BIN tests/testdata/control_images/text_renderer/background_fillcolor/background_fillcolor.png
  16. BIN ...s/testdata/control_images/text_renderer/background_offset_mapunits/background_offset_mapunits.png
  17. BIN tests/testdata/control_images/text_renderer/background_offset_mm/background_offset_mm.png
  18. BIN tests/testdata/control_images/text_renderer/background_opacity/background_opacity.png
  19. BIN tests/testdata/control_images/text_renderer/background_outline/background_outline.png
  20. BIN ...ta/control_images/text_renderer/background_point_buffer_pixels/background_point_buffer_pixels.png
  21. BIN ...ges/text_renderer/background_point_center_buffer_pixels/background_point_center_buffer_pixels.png
  22. BIN ...ontrol_images/text_renderer/background_point_center_mapunits/background_point_center_mapunits.png
  23. BIN tests/testdata/control_images/text_renderer/background_point_mapunits/background_point_mapunits.png
  24. BIN ...enderer/background_point_multiline_buffer_mapunits/background_point_multiline_buffer_mapunits.png
  25. BIN ..._images/text_renderer/background_point_multiline_mapunits/background_point_multiline_mapunits.png
  26. BIN ...mages/text_renderer/background_point_right_buffer_pixels/background_point_right_buffer_pixels.png
  27. BIN .../control_images/text_renderer/background_point_right_mapunits/background_point_right_mapunits.png
  28. BIN tests/testdata/control_images/text_renderer/background_radii_mapunits/background_radii_mapunits.png
  29. BIN tests/testdata/control_images/text_renderer/background_radii_mm/background_radii_mm.png
  30. BIN .../control_images/text_renderer/background_rect_buffer_mapunits/background_rect_buffer_mapunits.png
  31. BIN tests/testdata/control_images/text_renderer/background_rect_buffer_mm/background_rect_buffer_mm.png
  32. BIN ...data/control_images/text_renderer/background_rect_buffer_pixels/background_rect_buffer_pixels.png
  33. BIN ...mages/text_renderer/background_rect_center_buffer_pixels/background_rect_center_buffer_pixels.png
  34. BIN .../control_images/text_renderer/background_rect_center_mapunits/background_rect_center_mapunits.png
  35. BIN tests/testdata/control_images/text_renderer/background_rect_mapunits/background_rect_mapunits.png
  36. BIN tests/testdata/control_images/text_renderer/background_rect_mm/background_rect_mm.png
  37. BIN ..._renderer/background_rect_multiline_buffer_mapunits/background_rect_multiline_buffer_mapunits.png
  38. BIN ...ol_images/text_renderer/background_rect_multiline_mapunits/background_rect_multiline_mapunits.png
  39. BIN tests/testdata/control_images/text_renderer/background_rect_pixels/background_rect_pixels.png
  40. BIN ..._images/text_renderer/background_rect_right_buffer_pixels/background_rect_right_buffer_pixels.png
  41. BIN ...ta/control_images/text_renderer/background_rect_right_mapunits/background_rect_right_mapunits.png
  42. BIN tests/testdata/control_images/text_renderer/background_rotation_fixed/background_rotation_fixed.png
  43. BIN ...s/testdata/control_images/text_renderer/background_rotation_offset/background_rotation_offset.png
  44. BIN tests/testdata/control_images/text_renderer/background_rotation_sync/background_rotation_sync.png
  45. BIN ...ta/control_images/text_renderer/background_svg_buffer_mapunits/background_svg_buffer_mapunits.png
  46. BIN tests/testdata/control_images/text_renderer/background_svg_buffer_mm/background_svg_buffer_mm.png
  47. BIN ...stdata/control_images/text_renderer/background_svg_buffer_pixels/background_svg_buffer_pixels.png
  48. BIN ...data/control_images/text_renderer/background_svg_fixed_mapunits/background_svg_fixed_mapunits.png
  49. BIN tests/testdata/control_images/text_renderer/background_svg_fixed_mm/background_svg_fixed_mm.png
  50. BIN ...testdata/control_images/text_renderer/background_svg_fixed_pixels/background_svg_fixed_pixels.png
  51. BIN tests/testdata/control_images/text_renderer/shadow_color/shadow_color.png
  52. BIN tests/testdata/control_images/text_renderer/shadow_enabled/shadow_enabled.png
  53. BIN tests/testdata/control_images/text_renderer/shadow_offset_angle/shadow_offset_angle.png
  54. BIN tests/testdata/control_images/text_renderer/shadow_offset_mapunits/shadow_offset_mapunits.png
  55. BIN tests/testdata/control_images/text_renderer/shadow_offset_pixels/shadow_offset_pixels.png
  56. BIN tests/testdata/control_images/text_renderer/shadow_opacity/shadow_opacity.png
  57. BIN ...testdata/control_images/text_renderer/shadow_placement_background/shadow_placement_background.png
  58. BIN tests/testdata/control_images/text_renderer/shadow_placement_buffer/shadow_placement_buffer.png
  59. BIN tests/testdata/control_images/text_renderer/shadow_radius_mapunits/shadow_radius_mapunits.png
  60. BIN tests/testdata/control_images/text_renderer/shadow_radius_mm/shadow_radius_mm.png
  61. BIN tests/testdata/control_images/text_renderer/shadow_radius_pixels/shadow_radius_pixels.png
  62. BIN tests/testdata/control_images/text_renderer/shadow_scale_150/shadow_scale_150.png
  63. BIN tests/testdata/control_images/text_renderer/shadow_scale_50/shadow_scale_50.png
  64. BIN tests/testdata/control_images/text_renderer/text_angled/text_angled.png
  65. BIN tests/testdata/control_images/text_renderer/text_blend_mode/text_blend_mode.png
  66. BIN tests/testdata/control_images/text_renderer/text_bold/text_bold.png
  67. BIN tests/testdata/control_images/text_renderer/text_buffer_color/text_buffer_color.png
  68. BIN tests/testdata/control_images/text_renderer/text_buffer_interior/text_buffer_interior.png
  69. BIN tests/testdata/control_images/text_renderer/text_buffer_mapunits/text_buffer_mapunits.png
  70. BIN tests/testdata/control_images/text_renderer/text_buffer_mm/text_buffer_mm.png
  71. BIN tests/testdata/control_images/text_renderer/text_buffer_opacity/text_buffer_opacity.png
  72. BIN tests/testdata/control_images/text_renderer/text_buffer_pixels/text_buffer_pixels.png
  73. BIN tests/testdata/control_images/text_renderer/text_color/text_color.png
  74. BIN tests/testdata/control_images/text_renderer/text_disabled_buffer/text_disabled_buffer.png
  75. BIN tests/testdata/control_images/text_renderer/text_line_height/text_line_height.png
  76. BIN tests/testdata/control_images/text_renderer/text_mapunits/text_mapunits.png
  77. BIN tests/testdata/control_images/text_renderer/text_multiline/text_multiline.png
  78. BIN tests/testdata/control_images/text_renderer/text_named_style/text_named_style.png
  79. BIN tests/testdata/control_images/text_renderer/text_opacity/text_opacity.png
  80. BIN tests/testdata/control_images/text_renderer/text_pixels/text_pixels.png
  81. BIN tests/testdata/control_images/text_renderer/text_point_bold/text_point_bold.png
  82. BIN tests/testdata/control_images/text_renderer/text_point_center_aligned/text_point_center_aligned.png
  83. BIN ..._images/text_renderer/text_point_center_multiline_aligned/text_point_center_multiline_aligned.png
  84. BIN tests/testdata/control_images/text_renderer/text_point_multiline/text_point_multiline.png
  85. BIN tests/testdata/control_images/text_renderer/text_point_right_aligned/text_point_right_aligned.png
  86. BIN ...ol_images/text_renderer/text_point_right_multiline_aligned/text_point_right_multiline_aligned.png
  87. BIN tests/testdata/control_images/text_renderer/text_rect_center_aligned/text_rect_center_aligned.png
  88. BIN ...ol_images/text_renderer/text_rect_multiline_center_aligned/text_rect_multiline_center_aligned.png
  89. BIN ...trol_images/text_renderer/text_rect_multiline_right_aligned/text_rect_multiline_right_aligned.png
  90. BIN tests/testdata/control_images/text_renderer/text_rect_right_aligned/text_rect_right_aligned.png
  91. BIN tests/testdata/control_images/text_renderer/text_with_background/text_with_background.png
  92. BIN tests/testdata/control_images/text_renderer/text_with_buffer/text_with_buffer.png
  93. BIN .../control_images/text_renderer/text_with_buffer_and_background/text_with_buffer_and_background.png
  94. BIN .../control_images/text_renderer/text_with_shadow_and_background/text_with_shadow_and_background.png
  95. BIN ...testdata/control_images/text_renderer/text_with_shadow_and_buffer/text_with_shadow_and_buffer.png
  96. BIN ...rer/text_with_shadow_below_buffer_and_background/text_with_shadow_below_buffer_and_background.png
  97. BIN ...enderer/text_with_shadow_below_text_and_background/text_with_shadow_below_text_and_background.png
  98. BIN ...s/text_renderer/text_with_shadow_below_text_and_buffer/text_with_shadow_below_text_and_buffer.png
  99. BIN ...ith_shadow_below_text_buffer_and_background/text_with_shadow_below_text_buffer_and_background.png
  100. BIN ...s/text_renderer/text_with_shadow_buffer_and_background/text_with_shadow_buffer_and_background.png
@@ -649,61 +649,6 @@ class QgsLabelCandidate
double cost;
};

/** \ingroup core
* Maintains current state of more grainular and temporal values when creating/painting
* component parts of an individual label (e.g. buffer, background, shadow, etc.).
*/
class QgsLabelComponent
{
%TypeHeaderCode
#include <qgspallabeling.h>
%End

public:
QgsLabelComponent();

// methods

QString text() const;
void setText( const QString& text );

const QgsPoint& origin() const;
void setOrigin( const QgsPoint& point );

bool useOrigin() const;
void setUseOrigin( const bool use );

double rotation() const;
void setRotation( const double rotation );

double rotationOffset() const;
void setRotationOffset( const double rotation );

bool useRotation() const;
void setUseRotation( const bool use );

const QgsPoint& center() const;
void setCenter( const QgsPoint& point );

bool useCenter() const;
void setUseCenter( const bool use );

const QgsPoint& size() const;
void setSize( const QgsPoint& point );

const QgsPoint& offset() const;
void setOffset( const QgsPoint& point );

const QPicture* picture() const;
void setPicture( QPicture* picture );

double pictureBuffer() const;
void setPictureBuffer( const double buffer );

double dpiRatio() const;
void setDpiRatio( const double ratio );
};


/**
* Class that stores computed placement from labeling engine.
@@ -736,14 +681,6 @@ class QgsPalLabeling : QgsLabelingEngineInterface
%End

public:
enum DrawLabelType
{
LabelText,
LabelBuffer,
LabelShape,
LabelSVG,
LabelShadow
};

QgsPalLabeling();
~QgsPalLabeling();
@@ -830,18 +767,6 @@ class QgsPalLabeling : QgsLabelingEngineInterface
//! @note not available in python bindings
// void drawLabelCandidateRect( pal::LabelPosition* lp, QPainter* painter, const QgsMapToPixel* xform );

static void drawLabelBuffer( QgsRenderContext& context,
const QgsLabelComponent &component,
const QgsTextFormat& format );

static void drawLabelBackground( QgsRenderContext& context,
QgsLabelComponent component,
const QgsTextFormat& format );

static void drawLabelShadow( QgsRenderContext &context,
const QgsLabelComponent &component,
const QgsTextFormat& format );

//! load/save engine settings to project file
void loadEngineSettings();
void saveEngineSettings();
@@ -856,6 +856,15 @@ class QgsTextFormat
*/
QFont font() const;

/** Returns a font with the size scaled to match the format's size settings (including
* units and map unit scale) for a specified render context.
* @param context destination render context
* @returns font with scaled size
* @see font()
* @see size()
*/
QFont scaledFont( const QgsRenderContext& context ) const;

/** Sets the font used for rendering text. Note that the size of the font
* is not used, and setSize() should be called instead to explicitly set the size
* of rendered text.
@@ -1021,6 +1030,21 @@ class QgsTextRenderer

public:

enum TextPart
{
Text,
Buffer,
Background,
Shadow
};

enum HAlignment
{
AlignLeft,
AlignCenter,
AlignRight,
};

/** Calculates pixel size (considering output size should be in pixel or map units, scale factors and optionally oversampling)
* @param size size to convert
* @param c rendercontext
@@ -1041,4 +1065,63 @@ class QgsTextRenderer
*/
static double scaleToPixelContext( double size, const QgsRenderContext& c, QgsUnitTypes::RenderUnit unit, bool rasterfactor = false, const QgsMapUnitScale& mapUnitScale = QgsMapUnitScale() );

/** Draws text within a rectangle using the specified settings.
* @param rect destination rectangle for text
* @param rotation text rotation
* @param textLines list of lines of text to draw
* @param context render context
* @param format text format
* @param drawAsOutlines set to false to render text as text. This allows outputs to
* formats like SVG to maintain text as text objects, but at the cost of degraded
* rendering and may result in side effects like misaligned text buffers.
*/
static void drawText( const QRectF& rect, double rotation, HAlignment alignment, const QStringList& textLines,
QgsRenderContext& context, const QgsTextFormat& format,
bool drawAsOutlines = true );

/** Draws text at a point origin using the specified settings.
* @param point origin of text
* @param rotation text rotation
* @param textLines list of lines of text to draw
* @param context render context
* @param format text format
* @param drawAsOutlines set to false to render text as text. This allows outputs to
* formats like SVG to maintain text as text objects, but at the cost of degraded
* rendering and may result in side effects like misaligned text buffers.
*/
static void drawText( const QPointF& point, double rotation, HAlignment alignment, const QStringList& textLines,
QgsRenderContext& context, const QgsTextFormat& format,
bool drawAsOutlines = true );

/** Draws a single component of rendered text using the specified settings.
* @param rect destination rectangle for text
* @param rotation text rotation
* @param textLines list of lines of text to draw
* @param context render context
* @param format text format
* @param part component of text to draw
* @param drawAsOutlines set to false to render text as text. This allows outputs to
* formats like SVG to maintain text as text objects, but at the cost of degraded
* rendering and may result in side effects like misaligned text buffers.
*/
static void drawPart( const QRectF& rect, double rotation, HAlignment alignment, const QStringList& textLines,
QgsRenderContext& context, const QgsTextFormat& format,
TextPart part, bool drawAsOutlines = true );

/** Draws a single component of rendered text using the specified settings.
* @param origin origin for start of text. Y coordinate will be used as baseline.
* @param rotation text rotation
* @param textLines list of lines of text to draw
* @param context render context
* @param format text format
* @param part component of text to draw. Note that Shadow parts cannot be drawn
* individually and instead are drawn with their associated part (eg drawn together
* with the text or background parts)
* @param drawAsOutlines set to false to render text as text. This allows outputs to
* formats like SVG to maintain text as text objects, but at the cost of degraded
* rendering and may result in side effects like misaligned text buffers.
*/
static void drawPart( const QPointF& origin, double rotation, HAlignment alignment, const QStringList& textLines,
QgsRenderContext& context, const QgsTextFormat& format,
TextPart part, bool drawAsOutlines = true );
};
@@ -771,7 +771,7 @@ void QgsLabelingGui::init()
mZIndexSpinBox->setValue( lyr.zIndex );

mRefFont = format.font();
mFontSizeSpinBox->setValue( format.font().pointSizeF() );
mFontSizeSpinBox->setValue( format.size() );
btnTextColor->setColor( format.color() );
mFontTranspSpinBox->setValue( 100 - 100 * format.opacity() );
comboBlendMode->setBlendMode( format.blendMode() );
@@ -73,9 +73,9 @@ void QgsLabelPreview::paintEvent( QPaintEvent *e )
if ( mFormat.buffer().size() != 0 )
{
mContext.setPainter( &p );
QgsLabelComponent component;
component.setText( text() );
QgsPalLabeling::drawLabelBuffer( mContext, component, mFormat );
QgsTextRenderer::Component component;
component.text = text();
QgsTextRenderer::drawBuffer( mContext, component, mFormat );
}

QPainterPath path;

1 comment on commit 0814347

@nirvn

This comment has been minimized.

Copy link
Contributor

@nirvn nirvn commented on 0814347 Oct 24, 2016

Wouhou!

Please sign in to comment.
You can’t perform that action at this time.