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

        1. drawTiledPixmap.png
          30 kB
          Christopher Manthei
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        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