Saving QPixmap as JPEG results in vertical lines - c++

A user installed our application to a server PC, shared the install directory as network drive Z: and now opens the app from different client PCs all over his shop. Everything works fine except for a naggling bug on one of the PCs:
On the Problem PC, the app can load .jpg files for inventory items just fine and show the corresponding QPixmap in a QLabel. When the inventory item he is currently viewing does not yet have an image assigned to it, he can open a file dialog, choose an image and display that correctly. However, saving the (new/changed) QPixmap as a .jpg stores it to disc as a series of colored vertical lines on a black background:
Saving is done via QPixmap::save( const QString & fileName, ...) with the file name set programmatically to "<some_id>.jpg" to designate the desired file format. Returns true, but the resulting file looks like modern art.
However, saving images works fine on the server and the other clients.
Both the server and the Problem PC run Windows XP at an identical patch level.
Process Explorer shows identical DLLs for the app process on server and Problem PC except for the Problem PC using dnsapi.dll, which the server doesn't.
Process Explorer also shows that on both server and client the Qt DLL used to deal with JPEGs is
\Device\LanmanRedirector\<server>\<app>\plugins\imageformats\qjpeg4.dll, and a drive-wide search on the Problem PC for qjpeg*.dll came up empty, so the app should use the same JPEG handling code on both computers.
Any suggestions?
(EDIT: added OS and patch status to problem description.)
EDIT: Solution: on the problem machine we had a 16 bpp colour depth. Setting that to 32 bpp solved our problem instantly. I also replaced
_pm.save( sDestFileName )
with
_pm.toImage().convertToFormat( QImage::Format_RGB32 ).save( sDestFileName )
so that we won't run into this on every old client PC running less than 32 bpp.

Here are a few things to try to isolate the problem:
Copy qjpeg4.dll to the client's working directory
Is the image corrupted when saving as PNG or GIF?
Convert your data to a QImage and work from that.
Consider the byte format (I usually use ARGB32 because it is int-aligned)
To test where the problem occurs, you might try converting the image to JPG format then viewing it in a debugging window.
The function below is from an OSS program I wrote. You might try using it then displaying the contents of the QImage referred to in the second parameter:
//! Saves image with JPEG compression in given quality (0 - 100, Qt's scale)
//! #param[in] in The lossless input image
//! #param[out] out The image to save to using JPEG compression
//! #param quality The quality level (0 - 100, 0 the most compressed)
//! #return The size of the saved image
quint32 Window::imageSaveLossy(QImage &in, QImage &out, quint8 quality)
{
quint32 retval;
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
QImage temp(in.size(), QImage::Format_ARGB32);
temp.fill(QColor(Qt::white).rgb());
QPainter painter(&temp);
painter.drawImage(0, 0, in);
temp.save(&buffer, "JPG", quality);
out.loadFromData(ba, "JPG");
retval = (quint32)ba.size();
buffer.close();
return retval;
}

Related

Display partially loaded image by QImage

I'm using QImage class from Qt to display the picture on screen. For some reason I need to display even not fully loaded images (e.g. when some data blocks are absent).
I would like to see something like this in result:
Standard image viewer for Windows can show me such broken images, but I can’t achieve same behavior with QImage. Image not displayed at all if broken. Is there a way to display a partially loaded image by QImage? Maybe I should use other Qt-related classes for that purpose?
QImage is probably too high level for this. If you do not want to go at the level of individual libraries for each format (e.g. libpng), you should consider using CImg. It is a small header only c++ library to read and process images, which use the low level libraries available to read images. From a loaded CImg you should be able to get the data into a QPixmap or QImage to display it.

QT widget How to get RGB Buffer from QCamera

I am porting an video streamer application to QT (from HTML), I just had the webcam working using QT, and now I want to know How can I get the RGB Video buffer from a QT Camera? All the samples I can see is capturing image to a file.
I am using QT Widgets and not QML since its a desktop application.
What I am trying to do is to get the buffer image of the camera, compress it and send to network.
And I want to trigger this manualy since I want to call the capture of next frame when all the compression and sending is done to prevent timing issue.

Pixmap screenshot convert to low-quality

i'm using qt creator to create sample Remote Assistance
my project have 2 part server and client
the client taking screenshot and send it to server but screenshot pictures have to much quality and it take too much size and is not good idea to send it from local area network or internet protocol
i need to resize image size or convert it to low quality so that can be almost Recognizable
this is my screenshot codes
void MainWindow::shootScreen()
{
originalPixmap = QPixmap(); // clear image for low memory situations
// on embedded devices.
originalPixmap = QGuiApplication::primaryScreen()->grabWindow(0);
//emit getScreen(originalPixmap);
updateScreenshotLabel();
}
void MainWindow::updateScreenshotLabel()
{
this->ui->label_2->setPixmap(originalPixmap.scaled(this->ui->label_2- >size(),
Qt::KeepAspectRatio,
Qt::SmoothTransformation));
}
Looks like you know how to change an image size, why isn't that enough?
Just do:
QPixmap smallPixmap = originalPixmap.scaled( QSize( originalPixmap.size().x()/4, originalPixmap.size().y()/4 ), Qt::KeepAspectRatio, Qt::SmoothTransformation );
And send smallPixmap instead of originalPixmap.
You could (should) also compress the image using QImageWriter, this will allow you to create an image compressed with jpeg format, which should also reduce the memory usage.
Check this, looks like they do what you are trying to do.

Taking camera photos in Cocos2d-x?

I saw Fennex attempt to access the camera api of Android within Cocos2dx. But on the project listed, I am not sure how I am going to access the camera and the photogallery. Is there a way to do this in Cocos2dx just as you do with Cocos2d?
Thank you!
This Post says there is no cocos2d-x class to do that but provided this code segments:
The gist of it is, on Android :
- call Java code to start an Intent
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
instance.startActivityForResult(cameraIntent, 31); //31 is an ID to recognize that intent yourself
get the Bitmap returned by the Intent
Bitmap original = (Bitmap) intent.getExtras().get("data");
eventually, scale it for your own needs (especially on lower-end device if you also get images from the library)
save it in the file format you want (I use png)
FileOutputStream stream = new FileOutputStream(path);
/* Write bitmap to file using JPEG or PNG and 80% quality hint for JPEG. */
bitmap.compress(CompressFormat.PNG, 80, stream);
bitmap.recycle(); //ensure the image is freed;
stream.close();
If you want the same for iOS look at this post

Real-time save in Qt

I am creating an app in Qt, similar to scribble (given in sample app). Purpose is to let user draw freehand and once finished, upload these drawing to net. As of now I am saving the drawing as PNG image every 5 seconds, so that the loss of data in an event of unexpected shut-down is minimum (I kept 5 sec to minimize write operations; Real real-time would be highly desirable).
But the problem is, I am saving the entire page as an image every 5 seconds, where the new data added may be few pixels. I was wondering if I could write ONLY the new pixels added into the disk; there is no constraint that I should use PNG while saving; I can convert the data to PNG at the end when user says he is finished.
The piece of code for saving very basic;
void SaveData(const QString &fileName, const char *fileFormat, QImage image)
{
mutex.lock();
QImage visibleImage = image;
if (visibleImage.save(fileName, fileFormat, 50))
{
system("sync");
mutex.unlock();
return true;
} else {
mutex.unlock();
return false;
}
}
I just wonder if REAL real-time save as the pixels getting added if possible..!
Thanks in advance
DK
I suggest you to use tiles to save the image. Split the canvas to many e.g. 64x64 rectangles. And save each rectangle into separate file. When something is changed, you need to rewrite only few small files instead of rewriting the whole picture.
Also there is another dangerous thing in your code. When you run QImage::save, it most likely will erase file contents and write new contents. If the system was shutted down between there two actions, your file will became empty. So it's important to write new contents to a temporary file and then move it to the proper location. Keeping several old version of a file also can be useful. Who knows how the file system will react on the shutdown.
You could maybe use a memory mapped file, something like:
QFile file("rawimage.dat");
file.open(QIODevice::ReadWrite);
// Make sure there is enough memory for the image
quint32 width = 16;
quint32 height = 16;
quint32 bpp32 = 4;
qint64 file_size = width * height * bpp32;
file.resize(file_size);
uchar* mem = file.map(0, file_size);
// make a QImage that uses the file as memory
QImage img(mem, 16, 16, QImage::Format_ARGB32);
// Do some drawing in the image
img.fill(0);
// finished with the file
file.unmap(mem);
file.close();
You will need to check that it actually flushes to disk correctly - I haven't tested this. Ideally on Windows you'd want to be able to call 'FlushViewOfFile' on the memory mapped handle to ensure that modified pages are written to disk. It doesn't look like there is a way of calling this in Qt so you might need to do something operating system specific here to ensure that the disk image is consistent when you want it to be.
You could create a list of QPainterPath objects of the drawn items, which are then rendered to the QImage. You'd need to change the mouse events to do the following: -
Mouse Down : create a new QPainterPath (painterPath) and call painterPath->moveTo
Mouse Move : call painterPath->LineTo
Mouse Up : Store the QPainterPath in a list.
In the paint event, you then pass each new QPainterPath to be drawn
To back up, every n seconds, open up a file and append a stream of the new QPainterPaths since the last time the list was saved.
To restore, open the file, stream them back in and draw them on to the Image.
This can be optimised to check for new items and not to bother saving if none exist. In addition, rather than being time based, you could maintain a number of points that are created in the QPainterPath and only save when it exceeds a certain number.
Note that if you do go down this route, you may also want to store Painter settings with each QPainterPath, if the user can also change things such as pen colour, width etc.
Other advantages come with using QPainterpath - for example, the user could open up one image and then a second, choosing to have it drawn on top of the first.
If you want real-time saving then I suggest you use an uncompressed bitmap format. Changing pixels would be as simple as seeking inside the file to the x-y co-ordinates, usually calculated as
file.seek(y * lineWidth + x * pixelDataSize);
file.write(pixelData);