I draw frequency spectrum of WAV file inside QImage (example: http://savepic.net/2350314.jpg). The WAV file may be long enough to not fit into screen considering good time resolution.
I need to be able to srcoll through entire file fast enough, possibly without filesystem reading operations.
So i have to keep large QImage in memory for fast scrolling. Another desigion would be slower, because it would require me to redraw QImage (QImages) every time user scrolls a screen.
Assuming the desigion with keeping large QImage in memory (1024x50000, for example) i must be able to display some part of that large QImage in the program window.
What is the solution with lowest cost? Using QScrollArea or maybe using QPainter method drawImage() with offset arguments?
I would definitely build a small custom widget and reimplement its paint() method with a QPainter (and scrolling with offsets etc).
Using QPixmap for showing the needed parts of the image should be faster then natively drawing (a part of) a QImage.
Related
I have a QAbstractListModel with custom objects as items. Each object has a QImage that is loaded from a database. I use ListView in QML to visualize it but I do not see any mean to represent QImage in the delegate. Image primitive seems to accept only URLs.
Is the only way for me to show QImages is to create a QQuickImageProvider with some custom system of a URL per element (looks like a total overkill)?
I think QQuickImageProvider is the proper way.
Also, I think you can use the word 'overkill' if you know exactly how the Qt internals work. Otherwise it's just guessing.
AFAIK there is a complex caching system of images (and other data) underneath, so once an image pixmap is loaded (and doesn't change) data retrieval is immediate. So no overkill at all, since in any case at some point you need to load those QImage, but just once.
I believe a QQuickImageProvider provides pointers to the cached data, and not the whole rasterized data every time. Moreover blitting operations are nowadays performed with hardware accelerations, so it's a single operation taking a fraction of millisecond.
In other words you end up having:
give me image with url "image://xyz"
Qt looks up in the cache and returns the data pointer or performs a full load of the image if not found
the QML renderer passes the data array to OpenGL
one single blit operation (microseconds) and you have it on screen
A QML ShaderEffect will bind a QImage to a GLSL Sampler2D. See the list of "how properties are mapped to GLSL uniform variables" in the ShaderEffect docs. Needs a few lines of GLSL writing in the ShaderEffect to pass pixels through, (will update this post with an example sometime, when I have access to my code), but the result is a fast, QSG-friendly all-QML element which can render QImages.
My current code follows this: Disk > bytearray > QImage (or QPixmap) > Painter
// Step 1: disk to qbytearray
QFile file("/path/to/file");
file.open(QIODevice::ReadOnly);
QByteArray blob = file.readAll();
file.close();
// Step 2: bytearray to QImage
this->mRenderImg = new QImage();
this->mRenderImg->loadFromData(blob, "JPG");
// Step 3: render
QPainter p(this);
QRect target; // draw rectangle
p.drawImage(target, *(this->mRenderImg));
Step 1 takes 0.5s
Step 2 takes 3.0s - decoding jpeg is the slowest step
Step 3 takes 0.1s
Apparently, decoding jpeg data is the slowest step. How do I make it faster?
Is there a third party library that can transform bytearray of jpeg data to bytearray of ppm that can be loaded to QImage faster?
Btw, Using QPixmap takes the same time as QImage.
I was able to reduce QImage load time significantly using libjpeg-turbo. Here are the steps
Step 1: Load .jpeg in memory filebuffer
Step 2a: Use tjDecompress2() to decompress filebuffer to uncompressedbuffer
Step 2b: Use QImage(uncompressedbuffer, int width, int height, Format pixfmt) to load the QImage
Step 3: Render
Step 2a and 2b combined offers atleast 3x speedup compared to QImage::loadFromData()
Notes
PixelFormat used in libjpeg's tjDecompress2() should match with format specified in step 2b
You can derive the width and height used in step 2b using tjDecompressHeader2()
I think your question is more addressing a end result of a design issue rather than the design issue itself. Here are my thoughts related to the loading times of jpegs or images in general in GUIs.
Loading of data from a harddrive is a common bottleneck of software design. You have to get the harddrive to spin to that location and pull it out and copy it to the ram. Then when you are ready, you have the ram push it to the video buffer or maybe to the graphics card.
An SSD will be much faster, but demanding this of your end user is not practical in most situations. Loading the image once on startup and never closing your program is a way to avoid hitting this delay multiple times.
It is a big reason why lots of programs have a loading bar or a splash screen when it is starting up, so that it doesn't have a slow user experience when pulling up data.
Some other ways that programs handle longer processes are with the classic hour glass, or the spinning beach ball, or the "wait a bit" gifs are common.
Probably the best example of handing lots of large jpegs is google maps or some of the higher quality photo manager programs such as Picasa.
Google maps stores many different resolutions of the same area, and tiles and then load then specific to the resolution that can be viewed. Picasa "processes" all the images it finds, and stores a few different thumbnails for each one that can be loaded much faster than the full resolution image (in most cases).
My suggestion would be to either store a copy of your jpeg at a lower resolution, load that one, and then after it is loaded, replace it with the high resolution one when it is loaded, or to look into breaking your image into tiles and load them as needed.
On another related note, if you UI is getting slowed down by the jpeg loading, move the loading part into a thread and keep your UI responsive!
Hope that helps.
You asked about third-party software - -
ImageMagick can do this task quickly (even with larger files):
convert 1.jpg 2.jpg 3.jpg outputfilenamehere.ppm
While you have the filestream open, you can do numerous operations...
Hope that helps,
Gette
I am developing a program that must calculate a color of each point on a 1024x1024 picture using a special algorithm. The color of a point represents some value. So each point is independent of other points and must be drawn separately. I do not have to refresh the picture too frequently. Actually, I need to display it only once.
What is the fastest approach to drawing separate pixels in Qt?
Can I get some sort of "screen memory" and write all the picture as an array of 4-byte sets, representing each pixel as 4 bytes in that memory?
The QImage class is optimized for pixel manipulation. You can instantiate one with the requred size and then either set the pixels individually setPixel, or access the raw data and manipulate them in place via bits(). Just be sure to use the correct format (e.g. RGBA values or color indices for 8-bit images)
The fastest solution may be to create a QImage, manipulate it (set the pixels) and then get Qt to draw it.
The QImage class is for fast IO, from the manual:
The QImage class provides a hardware-independent image representation that allows direct access to the pixel data, and can be used as a paint device.
The QImage class supports several image formats described by the Format enum. These include monochrome, 8-bit, 32-bit and alpha-blended images which are available in all versions of Qt 4.x.
There is information on pixel manipulation in the Detailed Description section.
To display it the simplest way would be to convert it to a pixmap with QPixmap::fromImage and then put it in a label with QLabel::setPixmap.
For more control, you could sub-class QWidget, overload the paintEvent, and draw the QImage with a QPainter with QPainter::drawImage.
You might try to use an OpenGL widget and the glDrawPixels function.
Is there a way to set the render target to a GDI bitmap in SlimDX so that as soon as the scene is rendered I can immediately BitBlt the render out of there for processing in another thread and continue rendering?
Is it necessary to render to a texture and then copy the contents out to the bitmap? I would like to be able to do this without any unnecessary copying. I'm going to need every speedup I can get.
Sorry, you do need to render to a RenderTarget then copy that resource into a Texture2D then you can map the data and get the pixels into your bitmap.
The memory for RenderTargets is marked for a special kind of use by the graphics card and cannot be read from directly
The memory for Textures can be marked so that it can be read but only through the API as it is still held on the graphics card (some exceptions but DirectX has to go with the lowest common denominator)
If you need the extra speed reuse the same bitmap or have an array of prepared bitmaps ready to fill and keep them on rotation.
And as ever, measure how much time these things are consuming with a profiler so that you can quantify bottlenecks.
I have a large display (about 1000x2000 pixels) and I'm doing the following to draw images to the screen:
QImage *pImage = GetImage(); // from wherever
QPainter painter(this);
painter.drawImage((0,0), *pImage); // this line takes over 100ms to complete.
The larger the screen is that I'm drawing to, the longer this paint takes. I guess the pImage is being memcpy'd and that's the difference. How can I reduce this overhead? I'm not trying to scale or anything here.
Thanks.
You're painting a QImage. Don't do that, try with a QPixmap instead.
From the QImage documentation:
QImage is designed and optimized for I/O, and for direct pixel access and manipulation, while QPixmap is designed and optimized for showing images on screen."
Depending on the platform, getting the QImage data into the format and location needed for painting, can be extremely expensive.
P.S.: There is no need to create QImages on the heap, as
QImage objects can be passed around by value since the QImage class uses implicit data sharing.
One simple improvement you can make is to draw only the area that needs updated (if you can). The QPaintEvent contains a rect for the changed area, and the QPainter::drawImage has overloads that can take rects for the portion to draw.
You might also look at the ImageConversionFlags options for faster options.