Not 100% what you are looking for but hopefully a start. This will only work for labels which are in Curved
placement mode. You need to select the layer from which you want to calculate the polygons based on the labels. Only the labels in the current view will be taken into account. The script iterates over all labels, creates a temporary line from each center point of each label character and finally creates a buffer based on the height.
# Access selected layer
labellayer = iface.layerTreeView().selectedLayers()[0]
# Get canvas, labels in canvas and current extend
mc = iface.mapCanvas()
lr = mc.labelingResults()
extent = mc.extent()
# Prepare temporary layer
vl = QgsVectorLayer('Polygon?crs=epsg:3857', 'polygon' , 'memory')
vlProv = vl.dataProvider()
# Helper Dict where we store the center points of each label character and the height
linePoints = {}
# Iterate over all labels
for lrl in lr.labelsWithinRect(extent):
# Create a temporary dict per each label and store the height + list for the points
if lrl.featureId not in linePoints:
linePoints[lrl.featureId] = {}
linePoints[lrl.featureId]["height"] = float(lrl.height)
linePoints[lrl.featureId]["points"] = []
if lrl.layerID == labellayer.id():
# Add each point to the point list
geom = QgsGeometry.fromRect(lrl.labelRect)
point = QgsPoint(geom.centroid().asPoint())
linePoints[lrl.featureId]["points"].append(point)
# Iterate over the helper dictionary
for key, value in linePoints.items():
# First we create a temporary line geometry of each of the character points
lineGeom = QgsGeometry.fromPolyline(value["points"])
# Finally we create a buffer polygon from the line using the height
polygonFeat = QgsFeature()
bufferGeom = lineGeom.buffer(value["height"], 100)
polygonFeat.setGeometry(bufferGeom)
vlProv.addFeatures([polygonFeat])
vl.updateExtents()
# Add the layer to the map
QgsProject.instance().addMapLayer(vl)
EDIT:
As mentioned by @Matt a different QgsGeometry.JoinStyle
can be applied. Unfortunately I couldn't find a perfect solution as sometimes half of the last character is clipped of. Another improvement is to devide the height by two so the buffer fits more accurate.
# Finally we create a buffer polygon from the line using the height
polygonFeat = QgsFeature()
bufferGeom = lineGeom.buffer((value["height"] / 2), 100, QgsGeometry.EndCapStyle(3), QgsGeometry.JoinStyle(0), 0)
polygonFeat.setGeometry(bufferGeom)