I have a QImage in a QGraphicsView which I need to show images continously. Some times I need to show the inverted images continuously. For this I use
img.invertPixels(QImage::InvertRgba);
But at this time, the display is flickering due to the continuous inverting process. How can I implement the inverting process without affecting the performance? The display seems to be smooth without invert. `
QImage img(byImageBuf, width, height, QImage::Format_Indexed8);
scene->clear();
if(bInvertPixel)
{
/* Inverted image */
img.invertPixels(QImage::InvertRgba);
}
scene->addPixmap(QPixmap::fromImage(img));
view->fitInView(0, 0, width, height, Qt::IgnoreAspectRatio);
view->update();`
Since you are using an indexed image type (QImage::Format_Indexed8) you can invert the color table and just toggle that:
if(bInvertPixel)
{
/* Inverted image */
img.setColorTable( invertedColorTable );
}
else
{
img.setColorTable( standardColorTable );
}
standardColorTable and invertedColorTable are arrays of QRgb values.
The beauty of the color table is that you do not have to update it every time you display your image; just set it once and forget about it. Connect a signal from a button for inverting the colors and set the color table there.
Related
How can I set Icon size in my application so that it's still scaled when the users uses Screen Scaling?
In my application I have a QToolBar in the MainWindow that seems to use an Icon size of 24x24. I have some QToolButton which seem to get an Icon size of 20x20 by default, so I had to manually set it to 24x24 in order to have all Icons with same size, with setIconSize(QSize(24, 24));. Works fine without scaling:
When the Desktop has some scaling enabled, the Icons with the Fixed size don't get scaled, this looks then like this:
Another use case that I have is showing Icons in QLabels, there I have to specify the size when converting QIcon to QPixmap, this also doesn't scale mImageLabel->setPixmap(icon().pixmap(QSize(24, 24)));
Is there any better why then multiplying with the scale factor? How to get the scale factor?
It looks like setting the fixed size prevents any scaling from Qt side so we need to manually adjust the size. In my case it seems that I can get the correct scale factor by dividing the logicalDpi by 96, which is the DPI with scaling factor 1. I'm not sure if this is the best solution for all uses cases (haven't tested against MacOS for example) but fixes my use case.
I wrote a simple class that scales all my fixed size to the correct value:
#include <QApplication>
#include <QDesktopWidget>
QSize ScaledSizeProvider::getScaledSize(const QSize &size)
{
return {static_cast<int>(size.width() * getXScaleFactor()), static_cast<int>(size.height() * getYScaleFactor())};
}
qreal ScaledSizeProvider::getXScaleFactor()
{
auto desktopWidget = QApplication::desktop();
return desktopWidget->logicalDpiX() / getReferenceDpiValue();
}
qreal ScaledSizeProvider::getYScaleFactor()
{
auto desktopWidget = QApplication::desktop();
return desktopWidget->logicalDpiY() / getReferenceDpiValue();
}
qreal ScaledSizeProvider::getReferenceDpiValue()
{
return 96.0;
}
And the simple fetch the correct value with:
ScaledSizeProvider::getScaledSize(QSize(24, 24))
My LineItem inheriting from QGraphicsLineItem can change its pen width.
I have created a boundingRect that uses the QGraphicsLineItem::boundingRect adjusted by pads that get calculated based on pen width and arrows. It works.
void LineItem::calculateStuff() // called on any change including pen width
{
qreal padLeft, padRight, padT;
padLeft = 0.5 * m_pen.width(); // if no arrows
padT = padLeft;
padRight = padLeft;
m_boundingRect = QGraphicsLineItem::boundingRect().adjusted(-padLeft, -padT, padRight, padT);
update();
}
QRectF LineItem::boundingRect() const
{
return m_boundingRect;
}
QPainterPath LineItem::shape() const
{
QPainterPath p;
p.addRect(m_boundingRect);
return p;
}
There is only one artifact that I get:
if I increase the pen width, then decrease it, I get traces:
these of course disappear as soon as i move mouse or any action (I had a hard time getting the screen shots)
As pretty as they are (seriously I consider them a "feature :-) ) - I am trying to eliminate them. I tried to remember previous bounding rectangle, and update the item with the previous bounding rectangle - i thought that was what the option was for - but it didn't work.
QRectF oldRect = selectedItem->boundingRect();
item->setItemPenWidth(p);
selectedItem->update(oldRect);
selectedItem->update();
My viewport has
setViewportUpdateMode(BoundingRectViewportUpdate);
If I change to
setViewportUpdateMode(FullViewportUpdate);
I don't get artifacts - but I think this will impact performance which is a major constraint.
How can I fix these artifacts - that only occur in that specific situation, decreasing pen width / decreasing bounding rect of line, without impacting performance ?
Simple fix... I had to add
prepareGeometryChange();
in my calculateStuff() function.
I have not seen any changes from this before, it is the first time I change my boundingRect that it does not update seamlessly.
I have a div shape with before: and after: so it looks like a cross shape (Rotated).
But now my problem is, that the background is logically also rotated. I'd like that the background image isn't rotated and the image should be the size of the div.
I already tried to add a transform rotate to the place where I added the background but it didnt rotate back. Also for the size I tried background-size to adjust it, didnt work either.
Here is my jsbin: http://jsbin.com/iYogaCE/29/edit
thanks in advance!
nick
Well, I tried for a while to get a version working with pure CSS and HTML, but I was unable to do so. I believe that double pseudo selectors, aka ::after and ::before, would allow it to be possible, but I don't think that you can do it in pure CSS in one object currently.
With that being said, the way I accomplished it using one element is the much more common way - by using a canvas. With canvas it becomes pretty simple. Hopefully the comments make it easy to understand
Live demo here
// Gets a list of all the canvases to create an X for
var canvases = document.getElementsByClassName('profile');
// Allows the X to be drawn on multiple canvases without being redrawn
var tempCanvas = drawX();
// Gives the canvases a background image (the person's profile)
// If you wanted different images for each you could easily create an array
// and iterate through it for each canvas
var background = new Image();
background.src = "http://asta-design.ch/gameotion/wp-content/uploads/2013/03/placeholder.jpg";
// Once the image has loaded, apply the Xs
background.onload = function() {
// Do it for each canvas
for(var i = 0, j = canvases.length; i < j; i ++)
{
// Gets the current canvas and context
var canvas = canvases[i];
var context = canvas.getContext('2d');
// Allows the portrait only to be shown through the generated X
context.globalCompositeOperation = "destination-atop";
// Draws the profile picture
context.drawImage(background, 0,0, canvas.width, canvas.height)
// Cuts out everything that is not within the X
context.drawImage(tempCanvas, 0, 0);
}
}
// Creates the X to use as the cut out
function drawX() {
// Creates a hidden canvas to draw the X on
var offscreenCanvas = document.createElement('canvas');
var offscreenCtx = offscreenCanvas.getContext('2d');
// The width/height of the original canvas, not sure why "canvas.width" doesn't work here...
var size = 200;
offscreenCanvas.width = size;
offscreenCanvas.height = size;
// Creates the rectangles sloped positively
offscreenCtx.save();
offscreenCtx.translate(3 * size / 4, 3 * size / 4);
offscreenCtx.rotate(Math.PI/4);
offscreenCtx.fillRect(-size/2, -size/2, size * .3, size);
// Loads the state before the first rectangle was created
offscreenCtx.restore();
// Creates the rectangles sloped positively
offscreenCtx.translate(3 * size / 4, 1 * size / 4);
offscreenCtx.rotate(-Math.PI/4);
offscreenCtx.fillRect(-size/2, -size/2, size * .3, size);
// Returns the canvas with the X
return offscreenCanvas;
}
You can't rotate a CSS background independently of the element it is attached to.
The only way you're going to be able to do this is to have the rotated content in an additional element inside your existing one, and only rotate the inner element.
eg:
<div> <-- background applied to this element
<div>....</div> <-- but this one is rotated
</div>
Now your background will remain static while the content inside it rotates.
If you can't have any extra markup, you could still achieve this without changing the HTML, by using CSS the :before selector to create an additional pseudo-element behind the main element. Apply the background to that instead of the main element; after that it's similar to what I described above with the extra markup.
Hope that helps.
I need to do something similar to QPainter::drawImage, but drawing a triangle part of the given picture (into a triangular region of my widget) instead of working with rectangles.
Any idea how I could do that, besides painfully trying to redraw every pixel?
Thanks for your insights!
If it is feasible for you to use a QPixmap instead of a QImage, you can set a bitmap mask for the QPixmap which defines which of the pixels are shown and which are transparent:
myPixmap->setMask(myTriangleMask);
painter->drawPixmap(myPixmap);
Here is another solution based on QImage:
MaskWidget::MaskWidget(QWidget* parent) : QWidget(parent) {
img = QImage("Sample.jpg"); // The image to paint
mask = QImage("Mask.png"); // An indexed 2-bit colormap image
QPainter imgPainter(&img);
imgPainter.drawImage(0, 0, mask); // Paint the mask onto the image
}
void MaskWidget::paintEvent ( QPaintEvent * event ) {
QPainter painter(this);
painter.drawImage(10, 10, img);
}
Mask.png is an image file with the same size as Sample.jpg. It contains an alpha channel to support transparency. You can create this file easily with The GIMP, for example. I added an alpha channel, changed all areas I want to have painted to transparent and all other areas to white. To reduce the size, I finally converted it to an indexed 2-bit image.
You could even create the mask image programmatically with Qt, if you need your triangle be computed based on various parameters.
I have a QMessagebox with a custom background image. Since there is some stuff on the top side of the background image I want to see, the text of the messagebox should be lowered. Does anybody know how I can do this? I already tried throwing in some white lines using br, so:
popup.setText("<font size =5 color =white ><br>""<br>""<br>""Are you sure you
want to erase the memory</font> ");
but this screws up the background picture. Is there any way I can move the "box" that contains the text to a lower position?
You could try to get the QMessageBox' layout, get the label which holds your text and increment the labels margin. This probably is a hack and might make your project unportable. Construct your QMessageBox, call hack and then exec the box.
void hack(QMessageBox* pMessageBox)
{
QGridLayout* grid = qobject_cast<QGridLayout*>(pMessageBox->layout());
if (grid)
{
QLabel* label = qobject_cast<QLabel*>((grid->itemAtPosition(0,1))->widget());
if (label)
{
label->setMargin(label->margin()+5); // whatever is suitable
}
}
}