Как показать QImage без копирования в QGraphicsScene

У меня есть собственный класс изображений, содержащий массив символов без знака со значениями RGB. Я хотел бы показать изображения, хранящиеся в этом классе, без их копирования в QGraphicsScene. Я могу сделать QImage с помощью

QImage image(data, width, height, width * 3, QImage::Format_RGB888);

без копирования моего изображения. Как я могу показать изображение в QGraphicsScene без глубокой копии данных?


person user3561614    schedule 19.08.2015    source источник
comment
Почему вы думаете, что такой образ будет делать глубокую копию? Этого не произойдет, если только вы не сможете указать код в Qt, который вызывает глубокую копию.   -  person Kuba hasn't forgotten Monica    schedule 19.08.2015
comment
Сначала он должен преобразовать QImage в QPixmap.   -  person Valentin Heinitz    schedule 19.08.2015
comment
Строка выше ведет к поверхностной копии. Но я абсолютно не знаю, что происходит после этой строки внутри qt. Например. мой следующий банкомат строки - QGraphicsPixmapItem* item = scene_.addPixmap(QPixmap::fromImage(image));, и он, кажется, даже не задокументирован, если у сцены_ есть право собственности на элемент. Вероятно, это так.   -  person user3561614    schedule 19.08.2015
comment
Будет создан объект QPixmap с копией данных, и вы можете удалить свои данные (или объект QImage) из памяти. Это должно быть сохранено.   -  person Valentin Heinitz    schedule 19.08.2015
comment
Неважно, кто чем владеет, и QPixmap, и QImage неявно разделяются.   -  person Kuba hasn't forgotten Monica    schedule 19.08.2015
comment
Если вы посмотрите на реализацию QPixmap на растровом бэкэнде, это просто QImage :)   -  person Kuba hasn't forgotten Monica    schedule 19.08.2015
comment
@KubaOber Он создал QImage, не копируя данные из экземпляра своего класса. Но вызов QPixmap::fromImage создает копию данных. Не совсем копия, но, по крайней мере, зарезервирована новая память для хранения данных изображения способом, оптимизированным для их отображения.   -  person Valentin Heinitz    schedule 19.08.2015


Ответы (2)


По умолчанию используется растровый движок/бэкенд, содержимое виджета верхнего уровня сохраняется как файл QImage. Нарисовать на нем QImageQPixmap тоже) можно быстро и без копий. QPixmap с растровым бэкэндом — это просто QImage, который имеет тот же формат, что и резервное хранилище. Пиксельное изображение обычно не представляет какой-либо собственный дескриптор ресурса, поскольку вы используете растровый бэкэнд, если вы явно не запрашиваете что-то еще.

Итак, что вы хотели бы сделать, так это напрямую drawImage из исходного изображения в реализации QGraphicsItem::paint. Что действительно происходит за кулисами, так это то, что paint выполняется в резервном хранилище - QImage, и это быстро и эффективно. Используемый вами QPainter работает с QImage!

Все, что вам нужно сделать, это реализовать QGraphicsImageItem, аналогичный QGraphicsPixmapItem. Никакого копирования и преобразования формата не требуется, если исходное изображение имеет тот же формат, что и изображение, поддерживающее окно верхнего уровня. А как бы ты это узнал? Просто спросите в резервном магазине, в каком формате он находится.

QImage::Format backingStoreFormat(QWidget * widget) {
  auto store = dynamic_cast<QImage*>(widget->backingStore()->paintDevice())
  return store ? store->format() : QImage::Format_Invalid;
}

Оставляю реализацию QGraphicsImageItem читателю :)

person Kuba hasn't forgotten Monica    schedule 19.08.2015

Для отображения изображений QPixmap является подходящим классом. QGraphicsScene предоставляет метод только для QPixmap.

QGraphicsPixmapItem * QGraphicsScene::addPixmap(const QPixmap & pixmap)

Однако класс QPixmap оптимизирован для отображения изображений, поэтому его нельзя создать с существующим блоком памяти. Поэтому, если вы собираетесь отображать данные своей памяти в виде изображения в QGraphicsScene, это кажется невозможным (при разумных усилиях).

Почему вы беспокоитесь о копировании данных из вашего класса в QPixmap? Есть ли доказательства того, что это будет узким местом в производительности?

Если нет, либо вы конвертируете свой класс непосредственно в QPixmap, либо используете QPixmap::fromImage(). Добавьте свое изображение, например:

myScene->addPixmap( QPixmap::fromImage(myImage) );
person Valentin Heinitz    schedule 19.08.2015
comment
Извините за объяснение этого новичка. Согласно вашему комментарию, вы, очевидно, новичок :-) - person Valentin Heinitz; 19.08.2015