Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-56364

QPainter::drawTiledPixmap does not work correctly with an image width > 2048

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.6.3
    • 5.6.0
    • GUI: Painting
    • None
    • Windows 10

    Description

      Using QPainter::drawTiledPixmap with a pixmap width > 2048 causes the image to repeat after 2048 pixel instead of after the actual width. The following sample triggers this (you need a big enough screen to stretch to the window to over 2048 pixel width in logical space. See also the attached image.

      #include <QtGui>
      #include <QWidget>
      #include <QApplication>
      class QTestWidget : public QWidget
      {
      	virtual void paintEvent(QPaintEvent* event) override
      	{
      		QPainter painter(this);
      		const QRect rect = contentsRect();
      		QImage img(rect.width(), 1, QImage::Format_ARGB32);
      		for (int x = 0; x < img.width(); ++x)
      		{
      			QColor color = QColor::fromHslF((double)x / img.width(), 1, 0.5);
      			img.setPixel(x, 0, color.rgba());
      		}
      
      		QImage img565 = img.convertToFormat(QImage::Format_RGB16);
      		{
      			QPainter painter565(&img565);
      			QBrush brush(img565);
      			// Triggers blend_tiled_rgb565 opague bug
      			painter565.fillRect(rect.adjusted(0, 0, 0, -rect.width() / 2), brush);
      		}
      
      		painter.drawTiledPixmap(rect.adjusted(0, rect.height() / 2, 0, 0), QPixmap::fromImage(img565));
      		// Triggers blend_tiled_argb bug
      		painter.drawTiledPixmap(rect.adjusted(0, 0, 0, -rect.height() / 2), QPixmap::fromImage(img));
      	}
      };
      
      int main(int argc, char *argv[])
      {
      	QApplication app(argc, argv);
      	QTestWidget test;
      	test.show();
      	return qApp->exec();
      }
      

      The error is in the function blend_tiled_argb in qdrawhelper.cpp:

      while (length) {
                  int l = qMin(image_width - sx, length);
                  if (buffer_size < l)
                      l = buffer_size;
                  const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
                  uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
                  op.func(dest, src, l, coverage);
                  x += l;
                  length -= l;
                  sx = 0;
      }
      

      Should be replaced with:

      while (length) {
                  int l = qMin(image_width - sx, length);
                  if (buffer_size < l)
                      l = buffer_size;
                  const uint *src = (const uint *)data->texture.scanLine(sy) + sx;
                  uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
                  op.func(dest, src, l, coverage);
                  x += l;
                  sx += l;
                  length -= l;
                  if (sx >= image_width)
                      sx = 0;
      }
      

      This way it would function the same as e.g. blend_tiled_generic_rgb64 above it in the same file. The same pattern is also used incorrectly in blend_tiled_rgb565. I've tested both on the current dev branch and the problem exists there as well.

      Attachments

        For Gerrit Dashboard: QTBUG-56364
        # Subject Branch Project Status CR V

        Activity

          People

            allan.jensen Allan Sandfeld Jensen
            christophermanthei Christopher Manthei
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes