将 QImage* 转换为 void* ,反之亦然
Posted
技术标签:
【中文标题】将 QImage* 转换为 void* ,反之亦然【英文标题】:Convert QImage* to void* and vice versa 【发布时间】:2018-02-19 09:23:03 【问题描述】:我正在开发 C++ QT 项目,其中包含一些模块通过一个控制器模块使用带有签名的函数相互通信:
notify(QString stream_id, const void* stream, unsigned __int64 size)
所以我问的是如何将 QT 数据类型主要转换为 QImage* 到 void*,反之亦然,以使用 void 指针及其大小发送数据,
我正在尝试使用此代码,但它不起作用:
void* imageVoidPtr = static_cast<void*>(&image);
StreamListener::getInstance()->notify(QString("Stream_Name"),imageVoidPtr,sizeof(imageVoidPtr));
------------- 编辑
我正在尝试使用以下方法检索数据:
void VideoView::receive(QString stream_id, const void* stream, unsigned __int64 size)
QByteArray data = QByteArray::fromRawData(reinterpret_cast<const char*>(stream), size);
QBuffer buffer(&data);
QImageReader reader(&buffer);
QImage img = reader.read();
-------- 编辑 2
Void* 缓冲区大小为 4 或 12 的代码有什么问题(在 sizeOf(QImage) 的情况下)并且没有给出正确大小的图像字节大小, 并且接收器中接收到的图像是空的(没有错误出现)。
谢谢
【问题讨论】:
它不工作? 您可能希望发送图像的内容而不是指向QImage
的指针,具体取决于您的框架,并取决于这是在发送进程内还是发送到另一个进程。看看QImage::bits()
或QImage::constBits
。
sizeof(imageVoidPtr)
将简单地评估为void *
的大小——不与QImage
本身相关的任何内容。
【参考方案1】:
令人惊讶的是,您期望这会起作用。
指针只是一个整数,它表示可以保存任意数据的内存地址。因此,无论它指向什么,指针总是相同的大小,因为它总是一个内存地址,并且它总是由固定数量的位表示,在 32 位构建中为 32,在 64 位构建中为 64。
QImage
将数据存储在堆上。实际的类只是数据的控制器。因此,无论图像有多大,sizeof()
都会为您提供相同的结果。
QImage
已经支持使用QDataStream
进行序列化和反序列化:
QImage img(100, 100, QImage::Format_Mono); // original image
QByteArray data; // data container
QBuffer buffer(&data); // io device
buffer.open(QIODevice::ReadWrite);
QDataStream stream(&buffer); // data stream
stream << img; // save img to data
// you can now use the data.data() pointer, convert to void, and send data.size() number of bytes and put it into another byte array on the other side
// then replicate the io dev and data stream steps too, omitted for brevity
QImage img2; // new image
buffer.seek(0); // go to beginning of data
stream >> img2; // read data into new image
qDebug() << (img == img2) << data.size(); // true, it is the same content, size is 723 bytes, that includes the image format and raw data
【讨论】:
【参考方案2】:使用QImage
save method:
QImage image;
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG"); // writes image into ba in PNG format
您现在可以像这样使用QByteArray
底层缓冲区:
void* imageVoidPtr = static_cast<void*>(ba.data());
StreamListener::getInstance()->notify(QString("Stream_Name"), imageVoidPtr, ba.size());
如果您需要设置特定于格式的选项(例如质量,用于压缩格式),请改用QImageWriter:
QByteArray ba;
QBuffer buffer(&ba);
QImageWriter writer(&buffer, "JPG");
writer.setQuality(100); //max quality for jpeg
writer.write(image);
在接收端,一切都应该很好,已经(使用QBuffer
和QImageReader
)。
【讨论】:
【参考方案3】:乍一看,这显然是导致您的代码无法工作的问题:
StreamListener::getInstance()->notify(QString("Stream_Name"),imageVoidPtr,sizeof(imageVoidPtr));
最后一个参数应该是 sizeof(QImage) 而不是如下:
StreamListener::getInstance()->notify(QString("Stream_Name"),imageVoidPtr,sizeof(QImage));
希望它以这种方式工作,但如果不是,最好能提及代码有什么问题,如果它不工作,输出或错误是什么?
【讨论】:
感谢您的回答,但t work, and i have edited the main post about what
s 在(编辑2)中的代码中有错误【参考方案4】:
我已经为这个问题找到了一个简单的解决方案,
在将数据作为 void* 发送时,我只是将 QImage 的地址提供给通知函数,而不需要大小:
QImage image = CreateImage(imageStreamByteArray);
StreamListener::getInstance()->notify(StreamsNames::VIDEO_DAT_IMAGE,&image,0);
在接收时,我使用了这种类型的投射,但没有使用尺寸:
void VideoView::receive(QString stream_id, const void* stream, unsigned __int64 size)
QImage *img = const_cast<QImage*>(reinterpret_cast<const QImage *>(stream));
updateDisplay(img);
谢谢
【讨论】:
似乎每个人都误解了您的问题,因为它比预期的要简单得多。原来你只需要传递一个指针。如果你最终不使用它,你是否通过任何大小都无关紧要。您最初的问题是您试图将指针值解释为图像,这也是为什么每个人都认为问题涉及实际图像数据传输的原因,而事实并非如此。 请记住,使用void*
很容易出现错误,如果图像对象碰巧被破坏,它可能会导致悬空引用。这就是为什么最好按值传递它的原因,它是一个 CoW 对象,这意味着它只会涉及浅拷贝,并且传递的值保证在必要时保持底层图像数据处于活动状态,因为它是引用算了。您还可以避免任何内存泄漏。以上是关于将 QImage* 转换为 void* ,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章
使用 QImage::loadFromData 将 cv::mat 转换为 QImage
使用 PySide 将 QImage 转换为 Numpy 数组