简体   繁体   English

在Qt中实时保存

[英]Real-time save in Qt

I am creating an app in Qt, similar to scribble (given in sample app). 我正在Qt中创建一个应用程序,类似于scribble(在示例应用程序中提供)。 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). 截至目前,我每5秒将绘图保存为PNG图像,因此在意外关闭事件中数据丢失最小(我保持5秒以最小化写入操作;真正的实时非常需要) 。
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. 但是问题是,我每5秒将整个页面保存为一张图像,其中添加的新数据可能只有几个像素。 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; 保存时我不应该使用PNG; I can convert the data to PNG at the end when user says he is finished. 当用户说他完成时,我可以在最后将数据转换为PNG。

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 DK

I suggest you to use tiles to save the image. 我建议你用瓷砖来保存图像。 Split the canvas to many eg 64x64 rectangles. 将画布拆分为许多例如64x64矩形。 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. 当您运行QImage::save ,它很可能会删除文件内容并写入新内容。 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. 理想情况下,在Windows上,您希望能够在内存映射的句柄上调用“ FlushViewOfFile”,以确保将修改后的页面写入磁盘。 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. 在Qt中看起来没有一种方法可以调用它,因此您可能需要在此处执行特定于操作系统的操作,以确保磁盘映像在您希望的情况下保持一致。

You could create a list of QPainterPath objects of the drawn items, which are then rendered to the QImage. 您可以创建绘制项目的QPainterPath对象的列表,然后将其渲染到QImage。 You'd need to change the mouse events to do the following: - 您需要更改鼠标事件才能执行以下操作:-

  • Mouse Down : create a new QPainterPath (painterPath) and call painterPath->moveTo 鼠标按下:创建一个新的QPainterPath(painterPath)并调用painterPath-> moveTo
  • Mouse Move : call painterPath->LineTo 鼠标移动:调用painterPath-> LineTo
  • Mouse Up : Store the QPainterPath in a list. 鼠标向上:将QPainterPath存储在列表中。

In the paint event, you then pass each new QPainterPath to be drawn 在paint事件中,然后传递要绘制的每个新QPainterPath

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. 若要备份,请每隔n秒打开一个文件,并附加自上次保存列表以来的新QPainterPaths流。

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. 另外,您可以维护在QPainterPath中创建的多个点,而不是基于时间,并且仅在其超过一定数量时才保存。

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. 请注意,如果你沿着这条路线走下去,你可能还想用每个QPainterPath存储Painter设置,如果用户也可以改变笔颜色,宽度等等。

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. 使用QPainterpath具有其他优点-例如,用户可以打开一个图像,然后打开第二个图像,选择将其绘制在第一个图像之上。

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 改变像素就像在文件内部寻找xy坐标一样简单,通常计算为

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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