Qt: получение изображения по сети и его отображение

Модератор: Модераторы разделов

IMB
Сообщения: 2567
ОС: Debian

Qt: получение изображения по сети и его отображение

Сообщение IMB »

Доброго дня!
Необходимо с удалённого сервера получить изображение и отобразить его, передача происходит по UDP.
Изображение передаётся частями в следующем формате:
- код пакета (2 байта)
- порядковый номер пакета (2 байта)
- размер данных в пакете (2 байта)
- данные
При получении выполняется следующий код:

Код: Выделить всё

QDataStream in(&answer, QIODevice::ReadOnly);
in.setVersion(QDataStream::Qt_4_7);

quint8 data[5];
in >> data[0] >> data[1] >> data[2] >> data[3] >> data[4];
............................

quint8 data1;
in >> data1;

char *jpeg = new char[(data[4] << 8) | data1];
in.readRawData(jpeg, (data[4] << 8) | data1);

image->fill_data((data[2] << 8) | data[3],
             (data[4] << 8) | data1,
             jpeg);
delete jpeg;

Сборка изображения из частей:

Код: Выделить всё

QByteArray jpg;
jpg.reserve(frame_size); //известный размер изображения
void Image::fill_data(const quint16 num, const quint16 size, const char *data)
{
    jpg.append(data);
    next_packet(num, size); // учёт пришедших частей
}

Отображения изображения:

Код: Выделить всё

QPixmap pixmap;
void Image::view_image()
{
    if (pixmap.loadFromData(jpg)) {
        pixmap.scaled(frame_width, frame_height);
        ui->pushButton->setIcon(QIcon(pixmap));
    } else
        ui->pushButton->setText(QString(tr("error load image")));
    setWindowTitle(QString("%1 bytes (%2 packets) in %3 msec").
                arg(frame_size, 0, 10).
                arg(num_packet, 0, 10).
                arg(timer.elapsed(), 0, 10));
    show();
}

Судя по отладочному выводу я получаю все пакеты с данными, но изображение не появляется, только кнопка с надписью "error load image".
Подскажите в чём ошибка?
Спасибо.

Спасибо сказали:
Аватара пользователя
Denjs
Сообщения: 1685
ОС: SuSe 10.2

Re: Qt: получение изображения по сети и его отображение

Сообщение Denjs »

очевидно что надо сравнить тот набор бинарных данных которые вы собрали, с тем набором бинарных данных которые лежат на сервере перед отправкой.
- изоражение может быть изначально битое или портиться "отсылальщиком"
- но скорее всего вы можете портить его при приеме/обработке в виду собственных ошибок.
QDroid - Среда исполнения и фреймворк для QtScript.
OTPD - Открытые драйвера промышленных принтеров чеков и этикеток (кроссплатформенная подсистема печати).
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Qt: получение изображения по сети и его отображение

Сообщение IMB »

Это я сейчас проверяю, у меня в основном вопрос по коду, так как только изучаю и, вполне возможно, то он не совсем корректен.
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Qt: получение изображения по сети и его отображение

Сообщение Voral »

В целях освоения с Qt писал для себя кросплатформенную утилиту для передачи изображений из clipboard по сети. До конца не довел, но передача работала. Посмотри может поможет.

PS За код сорри, не рассчитывал ее ни продолжать писать, ни кому то отдавать...
У вас нет необходимых прав для просмотра вложений в этом сообщении.
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Qt: получение изображения по сети и его отображение

Сообщение IMB »

В функцию отображения изображения вставил отладочный код вида:

Код: Выделить всё

void Image::view_image()
{
    qDebug() << "jpeg data"
             << QString::number((unsigned char)jpg.at(0), 16)
             << QString::number((unsigned char)jpg.at(1), 16)
             << QString::number((unsigned char)jpg.at(2), 16)
             << QString::number((unsigned char)jpg.at(3), 16)
             << "..."
             << QString::number((unsigned char)jpg.at(jpg.size() - 3), 16)
             << QString::number((unsigned char)jpg.at(jpg.size() - 2), 16)
             << QString::number((unsigned char)jpg.at(jpg.size() - 1), 16)
             << QString::number((unsigned char)jpg.at(jpg.size()), 16);
    if (pixmap.loadFromData(jpg)) {
        pixmap.scaled(frame_width, frame_height);
        ui->pushButton->setIcon(QIcon(pixmap));
    } else
        ui->pushButton->setText(QString(tr("error load image")));
    setWindowTitle(QString("%1 bytes (%2 packets) in %3 msec").
                arg(frame_size, 0, 10).
                arg(num_packet, 0, 10).
                arg(timer.elapsed(), 0, 10));
    show();
}

Его вывод:

Код: Выделить всё

jpeg data "ff" "d8" "ff" "e0" ... "b8" "a1" "4b" "0"
Corrupt JPEG data: 1 extraneous bytes before marker 0xd9
JPEG datastream contains no image

Что я вижу, заголовок JPEG корректен, а вот с окончанием изображения проблемы, там ожидается 0xFFD9.
Что странно, на передающей стороне изображение просматривается нормально - изображение захватывается с CMOS и кодируется.
Qt насколько критично к данным?
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Qt: получение изображения по сети и его отображение

Сообщение Voral »

я б на вашем месте пакет дополни еще контрольной суммой и признаком конца. Может получаете лишний мусор. Сбросьте все что получили в файл да сравните с исходным. Помню мне в отладке так же помогал метод QByteArray::toHex()

А потом, имхо, мне кажется не очень прaвильный выбор использование UDP, тем более что изображение может отправляться частями.
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Qt: получение изображения по сети и его отображение

Сообщение IMB »

Voral писал(а):
05.07.2011 15:08
я б на вашем месте пакет дополни еще контрольной суммой и признаком конца.

Не могу, требования протокола. Слишком усложнять его нельзя, так как по нему должен работать ещё PLIS.
Voral писал(а):
05.07.2011 15:08
А потом, имхо, мне кажется не очень прaвильный выбор использование UDP, тем более что изображение может отправляться частями.

UDP выбран из соображений простоты и быстродействия, предполагается пересылать достаточно большие изображение с минимальными задержками, этакий вариант видео.
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Qt: получение изображения по сети и его отображение

Сообщение IMB »

Кажется я нашёл виновного:

Код: Выделить всё

QByteArray jpg;
void Image::fill_data(const quint16 num, const quint16 size, const char *data)
{
    qDebug() << "input data"
             << QString::number((unsigned char)data[0], 16)
              << QString::number((unsigned char)data[1], 16)
              << QString::number((unsigned char)data[2], 16)
              << QString::number((unsigned char)data[3], 16)
              << QString::number((unsigned char)data[4], 16)
              << QString::number((unsigned char)data[5], 16);
    qDebug() << "jpeg size before" << jpg.size();
    jpg.append(data);
    qDebug() << "input jpeg"
            << QString::number((unsigned char)jpg[0], 16)
             << QString::number((unsigned char)jpg[1], 16)
             << QString::number((unsigned char)jpg[2], 16)
             << QString::number((unsigned char)jpg[3], 16)
             << QString::number((unsigned char)jpg[4], 16)
             << QString::number((unsigned char)jpg[5], 16);
    qDebug() << "jpeg size after" << jpg.size();
    next_packet(num, size);
}

И вывод, для первого пакета:

Код: Выделить всё

input data "ff" "d8" "ff" "e0" "0" "10"
jpeg size before 0
input jpeg "ff" "d8" "ff" "e0" "0" "0"
jpeg size after 4

Насколько я понимаю добавление данных в QByteArray останавливается на первом 0, иначе как можно объяснить подобный вывод?

Да, проблема была в этом. Модифицировал функцию добаления данных в массив до jpg.append(data, size);
Вывод:

Код: Выделить всё

input data "ff" "d8" "ff" "e0" "0" "10"
jpeg size before 0
input jpeg "ff" "d8" "ff" "e0" "0" "10"
jpeg size after 1400

Как результат:
- могу просмотреть картинку записанную в файл, перед ей выводом

Код: Выделить всё

QFile file("/tmp/test.jpeg");
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
    qDebug() << "can't open file";
file.write(jpg);
file.close();

- отладочный вывод перед выводом

Код: Выделить всё

jpeg data size 59360 "ff" "d8" "ff" "e0" ... "d2" "85" "b1" "0"
Corrupt JPEG data: premature end of data segment

Вижу нормальный размер, но окончание при этом всё равно не корректно.
Спасибо сказали:
IMB
Сообщения: 2567
ОС: Debian

Re: Qt: получение изображения по сети и его отображение

Сообщение IMB »

И осталось последнее, отобразить изображение в натуральный размер поверх кнопки:

Код: Выделить всё

QPixmap pixmap;
QByteArray jpg;
void Image::view_image()
{
    if (pixmap.loadFromData(jpg)) {
        setWindowTitle(QString("%1 bytes (%2 packets) in %3 msec").
                    arg(frame_size, 0, 10).
                    arg(num_packet, 0, 10).
                    arg(timer.elapsed(), 0, 10));
        ui->pushButton->setIcon(QIcon(pixmap.scaled(frame_width, frame_height)));
    } else
        ui->pushButton->setText(QString(tr("error load image")));
    show();
}

Изображение нормально загружается в pixmap и отображается на кнопке, но... Отображается в маленьком размере, примерно 16х16, вместо ожидаемого 800х600.
Изображение достаточно корректное, если в этой функции перед выводом изображения его записать в файл, то полученный файл нормально открывается, проверял Gimp 2.4.7 и Geeqie 1.0alpha1.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Qt: получение изображения по сети и его отображение

Сообщение NickLion »

До setIcon():

Код: Выделить всё

ui->pushButton->setIconSize(QSize(frame_width, frame_height));


ну, и .scaled(...) наверное лишнее
Спасибо сказали: