I have a 4 channel png image with 8x8 Pixels that is loaded by a QImage. The QImage is then scaled by a factor of 200, so the image will have a new resolution of 1600x1600, each original pixel having a size of 200x200. But when this image is added to a QLabel through the means of a QPixmap and shown on screen, the drawn pixels will have slightly different sizes.
I've taken screenshots with Gimp and looked at the painted image more closely. It seems that every other pixel is slightly bigger than it should be, 201 instead of 200 pixels wide for example. The very last pixel in a row will then be smaller to compensate, so that the entire image has the correct size in the end.
This does not happen for all scaling factors, 100 is fine for example and so are factors that are a power of 2, such as 256.
My original approach was using a QGraphicsView and a QGraphicsPixmapItem in which case I scaled the GraphicsItem instead of the image. The effect was the same.
What effect am I seeing here? And what, if anything, can be done about it?
The code to reproduce this issue is very straightforward
int scale = 200;
image = QImage("some image file");
QPixmap pixmap = QPixmap::fromImage(image.scaled(image.size() * scale));
some_label->setPixmap(pixmap);
Turns out the easiest solution to my problem is to use QOpenGLWidget in the QGraphicsView:
setViewport(new QOpenGLWidget);
This single line in the constructor will result in much higher precision when scaling an image with the caveat of adding OpenGL as a dependency.
Another gotcha with this approach is that calling setViewport invalidates many of the settings done on a QGraphicsView. So if the view is set up in a UI file, as in my case, make sure to call other setters after calling setViewport.
I could not find a better solution that would work without OpenGL, short of writing my own rasterizer of course.
Related
I'm using Qt's GraphicsView/GraphicsScene framework, and I have to draw some line items.
To be sure these items are always visible (independant of the zoom level) I use a cosmetic pen, with a size of 3 (for example) so I always get lines of 3 pixels width drawn on screen.
But these items doesn't receive mouse events (such as hoverEnterEvent/hoverLeaveEvent) when I'm zooming out a lot.
I've digged in the code, and it appears that all collisions tests are done with the return value of the shape() function.
So I've tried to re-implement "shape()" and also "contains()" and "collidesWithPath()" methods, but I still have problems to detect collisions (because when zoom is changed, I need to re-update the shape for example).
Is there any tricks to do that ?
In an efficient way ? (without re-updating the item's shape at every zoom change)
Thanks
I have a QImage and a QPainter that paints on this image. After painting I tried to insert this QImage to QTextDocument with QTextCursor's insertImage method :
QImage image(width ,height,QImage::Format_RGB32);
QPainter paint;
paint.begin(&image);
paint.drawText(25,25,someText);
paint.end();
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.insertImage(image);
But after doing this what I got is a text with a low resolution or a line width saggy pixels like in this image :
!(http://imgim.com/4698inciz7774617.png)line image
I tried setting QTextDocument's layout's paint device but it gave an error because of null pointer, this is most probably because of the document does not have a layout
I tried setting render hints of painter but it does not work too.
I inserted some html before the image in the document but they are good in terms of resolution, also there are no problem in flat lines.
When I show this document in a QTextEdit it seems fine, but when this is in a pdf file in a preview or something something goes wrong.
My printer is defined like that in preview :
QPrinter printer(QPrinter::HighResolution);
QPrinter highprinter(QPrinter::ScreenResolution);
printer.setPaperSize(QPrinter::A4);
And I call QTextDocument's print method for printing.
Do you have any solutions for this?
thanks
Saggy pixels can be eliminated somehow with : QPainter::setRenderHint(QPainter::Antialiasing, true); however it seems it does not eliminate saggy pixels in letters very much.
Other way of eliminating saggy pixels fully is creating a document with large pixel sizes (resolution) and increasing size of the image.After that we can increase font point size and line widths it prevents aliasing as I saw in my trials.
//increasing line width when drawing line
paint.setPen(QPen(Qt::gray,20, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
//increasing font's point size when using text
qFont2.setPointSize(100);
paint.setFont(qFont2);
However increasing font point size does not prevent aliasing when the image's pixel size (resolution) remains same
I am able to paint a pixmap by using QPainter::drawPixmap, but I am having trouble with the sizing. The pixmap is being drawn onto many different scenes. Some of the scenes are very large, and some are very small. This results in the pixmap drawn being either looking very large or very small, depending on the size of the scene (or viewport, whatever its called). I need the pixmap to look the same size everytime, regardless of the dimensions of the scene it is being placed into.
Basically, I want it to work similar to drawPoint, where you can specify the length and width of the point in pixels, so the point looks the same size every time.
The following line of code is inside my paint function of the QGraphicsItem I subclassed:
painter_p->drawPixmap( pos(), MYPIXMAP );
with pos() returning the QPointF I need to draw the pixmap at.
Can't you use QGraphicsPixmapItem? It'd do exactly what you want.
I'm looking for the fastest way of:
merging (it means making one image from couple of images, putting one on other with respect to their alpha values)
display images
in Qt. This is my solution:
//------------------------------------------------------------------------------------
QImage image1 (width, height, QImage::Format_ARGB32);
QImage image2 (width, height, QImage::Format_ARGB32);
QImage image3 (width, height, QImage::Format_ARGB32);
/*
some operations with images
*/
QPainter displayPainter (this);
displayPainter.drawImage (topLeft, image1, area);
displayPainter.drawImage (topLeft, image2, area);
displayPainter.drawImage (topLeft, image3, area);
//------------------------------------------------------------------------------------
If there exists anything better, faster? I found information, that QPixmap is better for displaying it on a screen, but this:
displayPainter.drawPixmap (.)
is slower then this:
displayPainter.drawImage (.).
------------------------------------------ EDIT ------------------------------------------
I want to add that I seen this question:
What is the most efficient way to display decoded video frames in Qt?
but in my case using QGLWidget is little bit complicated. I'm using necessitas and this is not stable with paintEvent in QGLWidget. With paintGL has no problem.
Regards,
I found solution to make my code more optimal. In my case, I deal with alpha blending of multiple images. I found in documentation,
that:
"Certain operations (such as image composition using alpha blending)
are faster using premultiplied ARGB32 than with plain ARGB32."
Using:
QImage image (width, height, QImage::Format_ARGB32_Premultiplied);
instead of:
QImage image (width, height, QImage::Format_ARGB32);
improved alpha blending making it 2 times faster!
Do you have any other ideas how to make it better?
You may consider the "Image Composition Example" code available in Qt examples. It seems to be what you are looking for ?
I'm working on an application where I'm drawing some rectangles on the screen, and then will need to manipulate the shapes (change their size, location). I tried to do something with .drawRect and clearing the shape each time I was manipulating it, but the RAM usage was spiking and then falling (presumeably because i keep reinitializing a new component and then removing it, and garbage collection was cleaning it out). This seems like its probably not the most efficient way to do it.
Is there a way for me to just create a shape once, and then move it around on a canvas (and change its width and height without all this RAM usage?
If all you're doing is changing it's offsets, and adjusting it's width and height without needing to fundamentally change the structure of the shape (such as rounding the corners of a rectangle of some such) you should be able to just maintain a reference to the Shape and adjust it's x, y, scaleX, scaleY properties to effect the changes.
You can try Degrafa to draw the rectangle.
To move the rectangle:
Changing the x and y or height and width property of the shape
Using the Flex Move Effect