Как эффективно сдвигать пиксели растрового изображения в Qt4

Я реализовал виджет выделенного текста с помощью Qt4. Сначала я нарисовал текстовое содержимое на растровом изображении. А затем нарисуйте часть этого растрового изображения на устройстве рисования, вызвав painter.drawTiledPixmap (offsetX, offsetY, myPixmap)

Мое воображение состоит в том, что Qt заполнит весь прямоугольник выделенного текста содержимым из myPixmap.

Есть ли еще более быстрый способ сдвинуть весь существующий контент на 1 пиксель влево и заполнить недавно открытую область шириной 1 пиксель и высотой N пикселей контентом из myPixmap?


person stanleyxu2005    schedule 26.04.2010    source источник


Ответы (4)


Что ж. Раньше я использовал этот трюк с более медленным оборудованием. Обычно буфер изображения выделяется вдвое шире, чем необходимо, с одной дополнительной строкой в ​​начале. Создайте изображение слева от буфера. Затем рисуйте изображение несколько раз, продвигая буфер на 1 пиксель за раз в буфере.

int w = 200;
int h = 100;
int rowBytes = w * sizeof(QRgb) * 2; // line buffer is twice as the width
QByteArray buffer(rowBytes * (h + 1), 0xFF); // 1 more line than the height
uchar * p = (uchar*)buffer.data() + rowBytes; // start drawing the image content at 2nd line
QImage image(p, w, h, rowBytes, QImage::Format_RGB32); // 1st line is used as the padding at the start of scroll
image.fill(qRgb(255, 0, 0)); // well. do something to the image

p = image.bits() - rowBytes / 2; //  start scrolling at the middle of the 1st (blank) line
for(int i=0;i<w;++i, p+=sizeof(QRgb)) {
    QImage  scroll(p, w, h, rowBytes, QImage::Format_RGB32); // scrool 1 pixel at a time
    scroll.save(QString("%1.png").arg(i));
}

Я не уверен, что это будет быстрее, чем просто изменить смещение изображения и нарисовать его ровно. Сегодняшнее оборудование действительно мощное, что делает многие старые приемы бесполезными. Но забавно разыгрывать малопонятные шутки. :)

person Stephen Chu    schedule 08.05.2010

Привет,

одна из возможностей добиться этого:

  1. Создайте QGraphicsScene + View и дважды поместите на него растровое изображение (как QGraphicsPixmapItem), чтобы они были рядом друг с другом.
  2. Измените размер представления, чтобы он соответствовал размеру (одного) растрового изображения.
  3. Затем, вместо того, чтобы перерисовывать растровое изображение, вы просто меняете положение области просмотра вида, переходя от одного растрового изображения к другому.
  4. Вернитесь в конец, чтобы создать петлю.

Это может быть или не быть быстрее (с точки зрения производительности) - я не тестировал. Но, может быть, стоит попробовать, хотя бы ради эксперимента.

person Robin    schedule 26.04.2010
comment
благодаря. но QGraphicsScene основан на координатах с плавающей точкой, а не на целочисленных. этот подход быстрее? - person stanleyxu2005; 27.04.2010
comment
Я думаю, что важно не использование qreal vs. int, а то, как рисунок обрабатывается внутри. Я предполагаю, что перемещение области просмотра представления намного более оптимизировано, чем фактическое рисование растрового изображения снова и снова для каждого кадра. Но, как я уже сказал: я не проводил никаких тестов или тестов с этим. Если попробуете, расскажите, пожалуйста, свои результаты, ладно? - person Robin; 29.04.2010

Ваш подход, вероятно, один из самых быстрых, поскольку вы используете низкоуровневые методы рисования. Вы можете реализовать промежуточный подход между рисованием низкого уровня и опцией QGraphicsScene: используя область прокрутки, содержащую метку.

Вот пример кода, который создает новую область прокрутки, содержащую текстовую метку. Вы можете автоматически прокручивать метку, используя QTimer для запуска эффекта прокрутки, что дает вам красивый виджет выделения.

QScrollArea *scrollArea = new QScrollArea();

// ensure that scroll bars never show
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

QLabel *label = new QLabel("your scrolling text");

// resize the scroll area : 50px length and an height equals to its content height.
scrollArea->resize(50, label->size().height());
scrollArea->setWidget(label);
label->show(); // optionnal if the scroll area is not yet visible

Текстовую метку внутри области прокрутки можно перемещать слева направо на один пиксель, используя QScrollArea::scrollContentsBy(int dx, int dy) с параметром dx, равным -1.

person Lohrun    schedule 05.05.2010

Почему бы просто не сделать это попиксельно? Из-за того, как работают кеши, записывать пиксель в предыдущий полностью, пока вы не дойдете до конца. Затем вы можете заполнить последний столбец, прочитав другое изображение.

Тогда его довольно легко оптимизировать с помощью SIMD; хотя на этом этапе вы начинаете заниматься оптимизацией для каждой платформы.

person Goz    schedule 11.05.2010