2015-05-06 5 views
1

Я пытаюсь использовать libpng, чтобы прочитать png от ресурс Qt. Улов: класс, выполняющий чтение , должен не иметь любые зависимости Qt.Использование QFile made istringstream как двоичный вход (для libpng)

На первом этапе, чтение 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 (предпочтительно независимый от платформы) istream из 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); 

Это фактически дает ISS, который, на первый взгляд, выглядит хорошо, когда говорят

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, похоже, не имеет двоичного партнера.

Вы видите, что я пропустил?

ответ

0

Как говорит Айк, кажется, на самом деле быть о различиях между текста в центре операторов «>>», «< <» и такие вещи, как «.str (..)» в отличие в двоично-центре команд например «.read» и «.write». Плюс это о правильной инициализации потоков. Когда я, наконец, получил программу делать то, что я хотел евангелие пошло что-то вроде этого:

Сначала я использовал простой stringstream наряду с 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 AND std :: stringstream :: out активировано одновременно, потому что комбинация показалась мне несколько дурацкой. Тем не менее, оба необходимы. Однако я обнаружил, что могу пропустить std :: stringstream :: binary. Но так как это, кажется, не наносит вреда, мне нравится держите его на удачу. Не стесняйтесь прокомментировать это суеверие! :-)

+0

Я мог ошибаться, но я бы подумал, что нужно двоичный флаг, но 'stringstream :: in' и' stringstream :: out' не обязательно, поскольку это должно быть состояние по умолчанию 'stringstream' (как входной, так и выходной), в отличие от 'istringstream' или' ostringstream'. –

+0

Вот что я думаю. Теперь я также тестировал только двоичный файл. Тем не менее: я видел в результатах, что это как указано в моем сообщении: в обоих случаях оба требуются. Двоичный по какой-то причине нет. Заданный png 32x32, 3 байта на пиксель, цвет 2, handdrawn мной, используя GIMP. Все это происходит на 64-битной машине Debian. –

+0

Это странный вопрос - довольно запутанный для меня и, возможно, специфический для компилятора. О, хорошо, это не помешает указать их! Обычно я нахожу iostreams настолько противоречивым, что я использую их очень косвенно или иногда просто предпочитаю функции C. Это одна из причин, по которой я не мог дать вам идеального ответа, но я рад, что у вас это работает. –

1

Вы работаете с потоками, как текстовые данные с помощью операторов лексического извлечения. Проверьте ios::binary, а также методы read и write, которые подходят при работе с бинарным потоком.

Я бы поступиться operator<< и operator>> прямо в вашем случае в пользу read и write. Используйте ostream::write для записи данных массива байтов, возвращаемых из QIODevice::readAll(), чтобы передать его содержимое во временный строковый поток, например, и использовать ostream::read в своих тестах для проверки его содержимого.

Хороший тестовый пример, чтобы убедиться, что вы правильно передали, - это написать тест, в котором вы читаете содержимое из QFile, используйте ostream::write для передачи его в поток двоичных выходных файлов (ofstream), а затем попробуйте загрузить его в программном обеспечении для изображений, чтобы убедиться, что все в порядке. Затем замените поток файлов потоком строк и передайте его libpng, когда у вас это работает.

+0

Спасибо за ваши намеки. Я считаю, что проверка достоверности - это то, принимает ли png_sig_cmp (..) содержимое потока. Это делается для моего подхода ifstream. Это не для iStringstream. В обоих рабочих процессах в него не входят операторы «<<" or ">>» и для iss.str (..): он заполняется либо с помощью QString (qfile.readAll()) в моем первом, либо в QByteArray (qfile.readAll()) в моей второй attepmt. Но безрезультатно. Естественно, я либо касался потоков для вывода (используя «<<" and ">>»), либо для отправки в libpng. Не сразу. –

+0

Попробуйте что-то вроде этого: 'QByteArray bytes = qfile.readAll(); vector buf (bytes.size()); bytes.read (& buf [0], buf.size()); ofstream out_file ("my_test.png", ios :: binary); out_file.write ((const char *) & buf [0], buf.size()); ' –

+0

Затем посмотрите, правильно ли открывается' 'my_test.png" 'в программном обеспечении для изображений. Если это так, вы знаете, что ваша логика для перехода от объекта QIODevice к объекту «ostream» работает правильно (на данный момент можно использовать строковые потоки), а остальная часть должна быть простой, если у вас все нормально работает. –