使用QFile将istringstream作为二进制输入(对于libpng)

时间:2015-05-06 13:52:59

标签: c++ qt qfile istringstream

我正在尝试使用libpng来读取png 一个Qt资源。问题:班级正在阅读 应该具有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。但是如何获得 a(最好是平台独立的)来自Qt资源吗?性能 这不是什么大问题,所以我最初想出了

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无效。我的第一反应是&#34;二进制&#34;。但是:

  1. istringstream iss(std :: stringstream :: in | std :: stringstream :: binary);感觉很对。
  2. QIODevice :: ReadOnly似乎没有二进制合作伙伴。
  3. 你看到我错过了吗?

3 个答案:

答案 0 :(得分:1)

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

我会在你的案件中彻底放弃operator<<operator>>,而赞成readwrite。使用ostream::write写入从QIODevice::readAll()返回的字节数组数据,将其内容传输到临时字符串流,例如,在测试中使用ostream::read来验证其内容。

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

答案 1 :(得分:0)

正如艾克所说,似乎确实存在差异 以文本为中心的运营商'&gt;&gt;','&lt;&lt;'和'.str(..)'相反的东西 以二进制为中心的命令,如'.read'和'.write'。再加上它 关于正确初始化流。当我终于得到这个程序 做我想要的福音是这样的:

首先,我在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(..)都会写入所需的字符数 数据中有多少个零。我最大的问题是 我不愿意在AND中使用std :: stringstream :: std :: stringstream :: out同时激活因为 组合对我来说似乎有些古怪。但两者都需要。 但是,我发现我可能会跳过std :: stringstream :: binary。 但是因为它似乎没有任何伤害我喜欢 保持好运。尽管如此,请随意评论这种迷信! : - )

答案 2 :(得分:0)

更干净,更少C-ish,更多Qt / C ++ -ish版本可以是:

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

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

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

此外,对于PNG,您现在可以关注already posted article,因为std::istringstream的类型为std::istream

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