I've been playing around with the QtConcurrent module, and I'm struggling to
understand one part of the QtConcurrent documentation on this page:
https://doc.qt.io/qt-5/qtconcurrentmap.html. Specifically, the section on
Concurrent Map-Reduce
(https://doc.qt.io/qt-5/qtconcurrentmap.html#concurrent-map-reduce). They have
a pseudo code example of taking a bunch of images in, scaling each original
image to a 100x100 pixel thumbnail in the mapped function, and then creating a
larger collage image made up of all of thumbnails in the reduce function.
What I'm struggling with is: is there any way to initialize the result
parameter of the reduce function, before it is initially called? Because I
think as they've written their example and/or the way they've defined
QtConcurrent::mappedReduced() there's no way to do what their pseudo-example
purports to show as cleanly as they describe it.
Here's the example pseudo-code they're provide:
void addToCollage(QImage &collage, const QImage &thumbnail)
{
QPainter p(&collage);
static QPoint offset = QPoint(0, 0);
p.drawImage(offset, thumbnail);
offset += ...;
}
QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled,
addToCollage);
The issue I'm seeing is that there doesn't appear to be any way to initialize
the "collage" QImage BEFORE the first call to addToCollage(). Instead, it seems
like behind the scenes, the mappedReduced() function creates a default
constructed QImage, and then passes that to addToCollage(). Then the call to
QPainter::drawImage() inside addToCollage() can't actually do anything because
the underlying QImage is null. Each successive call to addToCollage() passes
the previously "modified" QImage in to be modified further, but since it's
still a null QImage, nothing actually happens.
I'm asking this because we're actually attempting to do something almost
exactly like their example - we want to make a big image out of a bunch of
little image thumbnails, where it takes a fair amount of processing to generate
each thumbnail. So ideally before calling mappedReduced() I'd be able to set up
the blank QImage with the desired final output size, and then somehow tell
mappedReduced to use THAT non-null QImage in the addToCollage() calls, but I
don't see a way to do that without a little extra work.
My approach at the moment is I've replaced the addToCollage() function with a
lambda function that captures an already initialized QImage, and then in that
lambda, I ignore the first parameter, and do the work on the captured image
instead. Something like:
QImage myImage(width, height, QImage:: Format_ARGB32); // <- create QImage
that is the size needed at the end
std::function<void(QImage &collage, const QImage &thumbnail)> addToCollage
= [&myImage](QImage &collage, const QImage &thumbnail) -> void
{
Q_UNUSED(collage) // <- completely ignore the "collage" QImage
that is passed in
QPainter p(&myImage); // <- operate on myImage instead
static QPoint offset = QPoint(0, 0);
p.drawImage(offset, thumbnail);
offset += ...;
};
QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled,
addToCollage);
This works, but I feel like I'm somehow missing the point of the
QtConcurrent::mappedReduced() design as it seems to imply that you're going to
stumble across a similar issue anytime your reduce function's result type is a
type that requires some initialization beyond whatever the default constructor
for that type does?
Sean
This e-mail, including any attached files, may contain confidential
information, privileged information and/or trade secrets for the sole use of
the intended recipient. Any review, use, distribution, or disclosure by others
is strictly prohibited. If you are not the intended recipient (or authorized to
receive information for the intended recipient), please contact the sender by
reply e-mail and delete all copies of this message.
_______________________________________________
Interest mailing list
[email protected]
https://lists.qt-project.org/listinfo/interest