2

我正在尝试使用 libpng 从 Qt 资源中读取 png。问题:进行读取的类应该具有 Qt 的任何依赖项。

第一步,阅读http://www.piko3d.net/tutorials/libpng-tutorial-loading-png-files-from-streams/#CustomRead我已经成功编写了一个函数

read_png(istream& in)

我还成功通过了一个普通的旧 ifstream

ifstream in("abs_path_to_png/icon.png");

read_png(..)并让它成功读取 png。但是如何从 Qt 资源中获取(最好是独立于平台的)istream?性能不是什么大问题,所以我最初想出了

bool Io_Qt::get_istringstream_from_QFile(QFile& qfile, istringstream& iss)
{
    // [.. Some checking for existence and the file being open ..]
    QString qs(qfile.readAll());
    iss.str(qs.toStdString());

    // I also tried: QByteArray arr(qfile.readAll()); iss.str(arr.data());

    return qfile.isOpen();
}

// Someplace else iss and qfile are created like this:

istringstream iss(std::stringstream::in | std::stringstream::binary);
QFile qfile(":/res/icon.png");
qfile.open(QIODevice::ReadOnly);

这实际上产生了一个问题,即乍一看,看起来不错,当说

cout << "'" << iss.str().c_str() << "'" << endl;

我明白了

'�PNG

'

不过,似乎存在一些空白问题。为了

ifstream in("abs_path_to_png/icon.png");
char c;
cout << "'";
for (int j=0;j<8;j++)
{
    in >> c;
    cout << c;
}
cout << "'" << endl;

产量

'�PNG'

虽然后者有效,但前者的变化最终导致 libpng 检查函数png_sig_cmp(..)拒绝我的 png 无效。我的第一个反应是关于“二进制”。然而:

  1. istringstream iss(std::stringstream::in | std::stringstream::binary); 感觉不错。
  2. QIODevice::ReadOnly 似乎没有二进制伙伴。

你看到我错过了什么吗?

4

3 回答 3

1

您正在使用流,就像它们是带有词法提取运算符的文本数据一样。查看ios::binary以及处理二进制流时适用的read和方法。write

在您的情况下,我会完全放弃operator<<并支持and 。用于写入返回的字节数组数据以将其内容传输到您的临时字符串流,例如,并在您的测试中用于验证其内容。operator>>readwriteostream::writeQIODevice::readAll()ostream::read

确保您正确传输的一个很好的测试用例是编写一个测试,您从 QFile 读取内容,用于ostream::write将其传输到二进制输出文件流 ( ofstream),然后尝试将其加载到图像软件中以查看如果没事的话。然后将您的文件流与字符串流交换,并将其传递给libpng您工作时。

于 2015-05-06T14:09:27.353 回答
0

正如艾克所说,它似乎确实是关于以文本为中心的运算符“>>”、“<<”和像“.str(..)”这样的东西与像“.read”这样的以二进制为中心的命令之间的区别,和写'。另外,它是关于正确初始化流的。当我终于让程序做我想做的事时,福音是这样的:

首先,我在 QFile 旁边使用了一个普通的字符串流:

// Explicitly setting flags should at least contain ::in and ::out
// stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary)
// However, the default constructor is perfectly fine.
stringstream ss;
QFile qfile(":/res/icon.png");
qfile.open(QIODevice::ReadOnly);

我传递给我的函数,现在看起来像这样:

bool Io_Qt::get_stringstream_from_QFile(QFile& qfile, stringstream& ss)
{
    // [.. some sanity checks..]
    QDataStream in(&qfile);
    uint len = qfile.size();
    char* c = (char*)malloc(len*sizeof(char));
    in.readRawData(c,len);
    ss.write(c,len);
    free (c);
    return true;
}

这条溪流被填满,大小合适。特别是因为 .write(..) 写入所需数量的字符,而不管数据中有多少个零。我最大的问题是我不愿意同时激活 std::stringstream::in 和 std::stringstream::out ,因为这种组合对我来说似乎有些古怪。然而两者都是需要的。但是,我发现我可能会跳过 std::stringstream::binary。但由于它似乎没有任何害处,我喜欢保留它以求好运。不过,请随意评论这个迷信!:-)

于 2015-05-06T18:47:54.613 回答
0

一个更干净、更少 C 风格、更多 Qt/C++ 风格的版本可以是:

QFile file(filePath);
file.open(QIODevice::ReadOnly);
QByteArray data = file.readAll();
std::istringstream iss(data.toStdString());

现在使用iss,在我的情况下,这是用于 libTIFF:

TIFF* tif = TIFFStreamOpen("MemTIFF", &iss);
// ...

此外,对于 PNG,您现在可以关注您已经发布的文章,因为std::istringstream它的类型是std::istream.

请注意,此解决方案涉及将文件数据完全加载到内存中。

于 2018-04-13T08:04:51.013 回答