I am trying to draw only the left border in QTextDocument. Since afaik QTextFrame doesn't support selective border so I am trying with assigning a textured brush to the text frame. Something like the following -
#include <QPainter>
#include <QTextFrameFormat>
#include <QTextCursor>
#include <QTextFrame>
#include <QTextEdit>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QTextDocument doc;
QPixmap map(1024, 1024);
QPainter p;
p.begin(&map);
p.setBackground(QBrush(Qt::transparent));
p.drawRect(QRect(0,0, 4, map.height()));
p.end();
QTextFrameFormat frameFormat;
QBrush bruh(map);
bruh.setColor(Qt::transparent);
frameFormat.setBackground(bruh);
auto cur = new QTextCursor(&doc);
auto frame = cur->insertFrame(frameFormat);
auto curf = new QTextCursor(frame);
curf->insertText("Hello this is qt program!");
QTextEdit e;
e.setDocument(&doc);
e.show();
return a.exec();
}
But this prints a black background even though the background is set to be transparent(I need a transparent background with only left red border).
I can't figure out what is wrong. Also, can there be any other way to have only a left border to a QTextFrame?
Try this:
QTextDocument doc;
QPixmap map(1024, 1024);
map.fill(Qt::white);
QPainter p;
p.begin(&map);
p.fillRect(QRect(0,0, 4, map.height()),QBrush(Qt::red));
p.end();
Related
I am trying to extract the pixel data from every frame, but when I try to get the pixmap it returns null. I thought that the pixmap would return the actual pixel data of what was on the screen, similar to glReadPixels but I think I am mistaken. I think it's meant to access the pixel map of the result of setPixmap.
Is there a way to access the raw pixels rendered on the screen? With the below example, "Hello World" is rendered on the screen and I want the actual pixel data of that label.
QWidget window;
window.resize(1280, 720);
window.show();
window.setWindowTitle(QApplication::translate("toplevel", "Top-Level Widget"));
QLabel *label = new QLabel(QApplication::translate("label", "Hello World"), &window);
label->move(500, 500);
label->raise();
label->show();
QPixmap pixmapVal = label->pixmap(Qt::ReturnByValue);
Cause
QPixmap:
The QPixmap class is an off-screen image representation that can be used as a paint device
In other words, it is a drawing canvas and, as any other canvas, if you have not drawn on it, it would be empty.
On the other hand QLabel serves as a view for the pixmap, not as its content, and when you try to access the pixmap of the label without having set one, it returns null.
Solution
There is of course a way to make a widget, the label in your case, content of the pixmap and access the pixel data. My approach to the this problem would be like this:
Create an empty pixmap with the size of the widget whos pixel content you want to access, e.g.:
QPixmap pixmap(widget->size());
pixmap.fill(Qt::transparent);
Use QWidget::render to render the content of the widget onto the pixmap:
widget->render(&pixmap);
Convert the pixmap to QImage and use QImage::pixel or QImage::pixelColor to access the rgb data of the pixel at (pixelX, pixelY) like this:
pixmap.toImage().pixelColor(pixelX, pixelY);
Example
Here is an example I have prepared for you to demonstrate how the proposed solution could be implemented:
#include "MainWindow.h"
#include <QApplication>
#include <QLabel>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
auto *label = new QLabel(QObject::tr("Hello World"), &w);
label->move(500, 500);
label->raise();
w.setWindowTitle(QObject::tr("Top-Level Widget"));
w.resize(1280, 720);
w.show();
QPixmap pixmap(label->size());
pixmap.fill(Qt::transparent);
label->render(&pixmap);
int pixelX = 10;
int pixelY = 5;
// Access image pixels
qDebug() << pixmap.toImage().pixelColor(pixelX, pixelY);
return a.exec();
}
Result
For the pixel at (10, 5) the example produces the following result:
QColor(ARGB 1, 0, 0, 0.156863)
I have code like this:
#include <QApplication>
#include <QGraphicsPolygonItem>
#include <QGraphicsScene>
#include <QGraphicsView>
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
QGraphicsScene scene;
QGraphicsView view;
view.resize(640, 400);
view.setScene(&scene);
auto polygon = new QGraphicsPolygonItem;
auto brush = QBrush(QColor(255, 0, 0));
polygon->setBrush(brush);
auto pen = QPen(brush, 20);
pen.setCapStyle(Qt::RoundCap);
polygon->setPen(pen);
QPolygonF polygonPath;
polygonPath << QPointF{-50, -50};
polygonPath << QPointF{100, -50};
polygonPath << QPointF{100, 100};
polygonPath << QPointF{-50, 100};
polygon->setPolygon(polygonPath);
scene.addItem(polygon);
view.show();
return app.exec();
}
Despite my round cap setting the polygon item gets rendered with straight caps.
Am I doing something obvious wrong here?
Not entirely sure but to get the result you're looking for when using a polygon path I think it's actually the 'join' style that needs to be set rather than the cap style. So change...
pen.setCapStyle(Qt::RoundCap);
to...
pen.setJoinStyle(Qt::RoundJoin);
So I needed border in QtextFrame in a pdf (QPrinter's pdf output). Following is the code I used
#include <QPainter>
#include <QTextFrameFormat>
#include <QTextCursor>
#include <QTextFrame>
#include <QTextEdit>
#include <QPrinter>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QTextDocument doc;
QPixmap map(1024, 1024);
map.fill(Qt::white);
QPainter p;
p.begin(&map);
p.fillRect(QRect(0,0, 4, map.height()), QBrush(Qt::red));
p.end();
QTextFrameFormat frameFormat;
QBrush bruh(map);
bruh.setColor(Qt::transparent);
frameFormat.setBackground(bruh);
frameFormat.setPadding(6);
auto cur = new QTextCursor(&doc);
auto frame = cur->insertFrame(frameFormat);
auto curf = new QTextCursor(frame);
curf->insertText("Hello this is qt program!");
QPrinter pdf;
pdf.setOutputFileName("E:\\test.pdf");
pdf.setOutputFormat(QPrinter::PdfFormat);
doc.print(&pdf);
QTextEdit edt;
edt.setDocument(&doc);
edt.show();
return a.exec();
}
But the pdf output is different from the what is shown in QTextEdit
pdf (Only a single black line no content)
Text Edit output which is what I needed
How to draw outline text on QImage with word wrap, alignment etc.?
I tried QPainterPath::addText() method, but it does not support word wrap and alignment.
This is how I draw text now:
path.addText(rect.bottomLeft(), font, text);
p.strokePath(path, pen);
p.drawText(rect, flag, text);
where
p - QPainter
rect - rectangle that contains the text
flag - Qt::AlignRight, Qt::TextWordWrap
but it looks like this
QPainter does not support this and neither does QPainterPath.
What you can do is use a QGraphicsSceneinstead. If you really have to create a QImage, you can always do that using its render() function.
To achieve this effect in a graphics scene you need a QGraphicsTextItem and a QTextCharFormat.
The outline is painted on top of the actual text, which looks like complete crap for any outline thicker than 1. Therefore you have to add another QGraphicsTextItem without outline on top of the first one.
Here is a full running example. Note that we can specify the width of the text, but not the height, you wold probably do that by clipping.
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QLabel>
#include <QPainter>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QTextDocument>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString text = "lorem ipsum dolor sit amet";
QFont font("Arial", 30);
QRect rect(100, 100, 300, 0);
QImage img(500, 500, QImage::Format_RGB32);
img.fill(0x00ffffff);
{
QPainter p(&img);
QGraphicsScene scene(img.rect());
QTextCharFormat charFormat;
charFormat.setFont(font);
charFormat.setTextOutline(QPen(Qt::red, 5, Qt::SolidLine));
QTextDocument document;
QTextCursor cursor = QTextCursor(&document);
cursor.insertText(text, charFormat);
QGraphicsTextItem outlineTextItem;
outlineTextItem.setPos(rect.topLeft());
outlineTextItem.setDocument(&document);
outlineTextItem.setTextWidth(rect.width());
scene.addItem(&outlineTextItem);
QGraphicsTextItem textItem(text);
textItem.setPos(rect.topLeft());
textItem.setTextWidth(rect.width());
textItem.setFont(font);
scene.addItem(&textItem);
scene.render(&p);
}
QLabel label;
label.setPixmap(QPixmap::fromImage(std::move(img)));
label.show();
return a.exec();
}
I found this solution: I draw the text in the buffer (using QPainter.drawText), calculate the SDF, and make outline.
https://en.wikipedia.org/wiki/Signed_distance_function
https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817
I'm trying to generate pixmaps with the following code
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(10050,10050);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
The above part works find. And I would like to paint on those pixmaps later, e.g.
QPixmap pixmap = pixmapList[10];
QPainter painter(&pixmap);
painter.drawPixmap(....); // this pixmap is 10*10
pixmapList[10]=pixmap;
or
QPainter painter(&pixmapList[10]);
painter.drawPixmap(....); // this pixmap is 10*10
but they both gave me "QPainter::begin: Paint device returned engine == 0, type: 2". May I ask the right way to paint on pixmaps in the pixmapList? Thanks very much!
Your code is OK, except that the pixmaps are too big (they occupy ~400MBytes each).
After making the pixmaps smaller, it works fine (shown for Qt 5):
#include <QGuiApplication>
#include <QPixmap>
#include <QPainter>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QList<QPixmap> pixmapList;
for (int i=0;i<50;++i){
QPixmap pixmap = QPixmap(1000,1000);
pixmap.fill(Qt::transparent);
pixmapList<<pixmap;
}
QPainter painter(&pixmapList[10]);
painter.drawLine(0, 0, 100, 100);
return 0;
}