My project requirement is that I can create an image with width of up to 36000 pixels (height much smaller).
(The image is rendered from a QGraphicsScene
).
I ran into a limitation: QPainter
limits its device size for raster painting:
void QRasterPaintEnginePrivate::systemStateChanged()
{
deviceRectUnclipped = QRect(0, 0,
qMin(QT_RASTER_COORD_LIMIT, device->width()),
qMin(QT_RASTER_COORD_LIMIT, device->height()));
....
}
// This limitations comes from qgrayraster.c. Any higher and
// rasterization of shapes will produce incorrect results.
const int QT_RASTER_COORD_LIMIT = 32767;
(My attempt to troubleshoot ... Rendering a large QGraphicsScene on a QImage clips it off)
So... I thought, can I create 2 images then add them ? (one at the end of each other)
if(wOutput > 32767)
{
QImage image1 = QImage(32767, hOutput, QImage::Format_Mono);
image1.fill(QColor(Qt::white).rgb());
QRectF source(0, 0, 32767, hOutput);
QRectF target(0, 0, 32767, hOutput);
QPainter painter;
painter.begin(&image1);
outputScene->render(&painter, target, source);
painter.end();
QImage image2 = QImage(wOutput - 32767, hOutput, QImage::Format_Mono);
image2.fill(QColor(Qt::white).rgb());
source = QRectF(32767, 0, wOutput - 32767, hOutput);
target = QRectF(0, 0, wOutput - 32767, hOutput);
painter.begin(&image2);
outputScene->render(&painter, target, source);
painter.end();
// now create a combination, add image2 at the end of image1
QImage image = QImage(wOutput, hOutput, QImage::Format_Mono);
painter.begin(&image);
painter.drawImage(0, 0, image1);
painter.drawImage(32767, hOutput, image2);
painter.end();
}
else
{
// just create the image
}
Looks very logical... but the output does not show image2
. Obviously... I am using the same raster painting... with the same limitation !
What other way can I add an image at the end of another ? ( note - my "large" size is a "width" so I don't even think I can use scanline
to copy pixels faster )
You can use QImage::scanLine
to get the pixel data and copy it.
However the QImage::Format_Mono
make it a little more complex because you have to consider the alignment of the pixel data (with QImage::Format_Mono
you have 1 bit per pixel, so 8 pixels into a byte).
I suggest to generate the first image using a width divisible by 8 (e.g 32760), so you can copy the row of the second image without shifting the bits.
Also the color table should be the same in the two source images.
You can do something like this:
int w1 = 32760;
QImage image1 = QImage(w1, hOutput, QImage::Format_Mono);
//grab the first image....
//....
int w2 = wOutput - w1;
QImage image2 = QImage(w2, hOutput, QImage::Format_Mono);
//grab the second image....
//....
int bytesPerLine1 = w1 / 8; //is divisible by 8
int bytesPerLine2 = ceil(float(w2) / 8.0f); //should be right :)
QImage image = QImage(wOutput, hOutput, QImage::Format_Mono);
image.setColorTable(image1.colorTable());
for(int i = 0; i < hOutput; ++i)
{
uchar* dstSL = image.scanLine(i);
uchar* src1SL = image1.scanLine(i);
memcpy(dstSL, src1SL, bytesPerLine1);
uchar* src2SL = image2.scanLine(i);
memcpy(&dstSL[bytesPerLine1], src2SL, bytesPerLine2);
}
I suggest also to read the QImage documentation: Pixel Manipulation and QImage::Format