Skip to content

Commit

Permalink
Merge pull request #4186 from t20100/revert-remove-raster-qt
Browse files Browse the repository at this point in the history
silx.gui: Updated OpenGL text rendering to use Qt when possible
  • Loading branch information
t20100 authored Oct 23, 2024
2 parents 450134d + 0e5c331 commit ea9dde8
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 4 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Release Notes
=============

2.1.2: 2024/10/23
-----------------

* Bug fixes

* `silx.gui``: Fixed memory leak: Updated OpenGL text rendering to use Qt when possible

2.1.1: 2024/08/13
-----------------

Expand Down
2 changes: 1 addition & 1 deletion src/silx/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

MAJOR = 2
MINOR = 1
MICRO = 1
MICRO = 2
RELEV = "final" # <16
SERIAL = 0 # <16

Expand Down
116 changes: 113 additions & 3 deletions src/silx/gui/_glutils/font.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# /*##########################################################################
#
# Copyright (c) 2016-2023 European Synchrotron Radiation Facility
# Copyright (c) 2016-2024 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand All @@ -21,19 +21,129 @@
# THE SOFTWARE.
#
# ###########################################################################*/
from __future__ import annotations
"""Text rasterisation feature leveraging Qt font and text layout support."""

__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "13/10/2016"


import logging
import numpy

from .. import qt
from ..utils.image import convertQImageToArray
from ..utils.matplotlib import rasterMathText


# Expose rasterMathText as part of this module
from ..utils.matplotlib import rasterMathText as rasterText # noqa
_logger = logging.getLogger(__name__)


def getDefaultFontFamily() -> str:
"""Returns the default font family of the application"""
return qt.QApplication.instance().font().family()


def rasterTextQt(
text: str,
font: qt.QFont,
dotsPerInch: float = 96.0,
) -> tuple[numpy.ndarray, float]:
"""Raster text using Qt.
It supports multiple lines.
:param text: The text to raster
:param font: Font to use
:param dotsPerInch: The DPI resolution of the created image
:return: Corresponding image in gray scale and baseline offset from top
"""
if not text:
_logger.info("Trying to raster empty text, replaced by white space")
text = " " # Replace empty text by white space to produce an image

dotsPerMeter = int(dotsPerInch * 100 / 2.54)

# get text size
image = qt.QImage(1, 1, qt.QImage.Format_Grayscale8)
image.setDotsPerMeterX(dotsPerMeter)
image.setDotsPerMeterY(dotsPerMeter)

painter = qt.QPainter()
painter.begin(image)
painter.setPen(qt.Qt.white)
painter.setFont(font)
bounds = painter.boundingRect(
qt.QRect(0, 0, 4096, 4096), qt.Qt.TextExpandTabs, text
)
painter.end()

metrics = qt.QFontMetrics(font)
offset = metrics.ascent() / 72.0 * dotsPerInch

# This does not provide the correct text bbox on macOS
# size = metrics.size(qt.Qt.TextExpandTabs, text)
# bounds = metrics.boundingRect(
# qt.QRect(0, 0, size.width(), size.height()),
# qt.Qt.TextExpandTabs,
# text)

# Add extra border
width = bounds.width() + 2
# align line size to 32 bits to ease conversion to numpy array
width = 4 * ((width + 3) // 4)
image = qt.QImage(
int(width),
int(bounds.height() + 2),
qt.QImage.Format_Grayscale8,
)
image.setDotsPerMeterX(dotsPerMeter)
image.setDotsPerMeterY(dotsPerMeter)
image.fill(0)

# Raster text
painter = qt.QPainter()
painter.begin(image)
painter.setPen(qt.Qt.white)
painter.setFont(font)
painter.drawText(bounds, qt.Qt.TextExpandTabs, text)
painter.end()

array = convertQImageToArray(image)

# Remove leading and trailing empty columns/rows but one on each side
filled_rows = numpy.nonzero(numpy.sum(array, axis=1))[0]
filled_columns = numpy.nonzero(numpy.sum(array, axis=0))[0]

if len(filled_rows) == 0 or len(filled_columns) == 0:
return array, offset
return (
numpy.ascontiguousarray(
array[
0 : filled_rows[-1] + 2,
max(0, filled_columns[0] - 1) : filled_columns[-1] + 2,
]
),
offset,
)


def rasterText(
text: str,
font: qt.QFont,
dotsPerInch: float = 96.0,
) -> tuple[numpy.ndarray, float]:
"""Raster text using Qt or matplotlib if there may be math syntax.
It supports multiple lines.
:param text: The text to raster
:param font: Font name or QFont to use
:param dotsPerInch: Created image resolution
:return: Corresponding image in gray scale and baseline offset from top
"""

if text.count("$") >= 2:
return rasterMathText(text, font, dotsPerInch)
return rasterTextQt(text, font, dotsPerInch)

0 comments on commit ea9dde8

Please sign in to comment.