简体   繁体   中英

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 eg 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 xy co-ordinates, usually calculated as

file.seek(y * lineWidth + x * pixelDataSize);
file.write(pixelData);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM