[Qt-interest] Map to view from inside QGraphicsItem::paint()
Samuel Rødal
sroedal at trolltech.com
Mon Oct 19 16:54:01 CEST 2009
Josiah Bryan wrote:
> Josiah Bryan wrote:
>> Josiah Bryan wrote:
>>> Hi All -
>>>
>>> Is there any way for me to be able to map my bounding rect inside a
>>> QGraphicsItem::paint() call to the actual pixel size on the screen?
>>>
>>> This is for the purpose of scaling large pixmaps to the "right" size. If
>>> my item is scaled up, and I only render the pixmap at the size of my
>>> item, the final pixmap will implicitly be scaled up by the view/scene
>>> scaling. I want to cache the scaled pixmap size that is the actual
>>> screen size and render a good quality pixmap at the same time.
>>>
>> Maybe I should explain more:
>>
>> I've got a large jpeg ( > 3MB on disk) that I'm rendering.
>>
>> Since I'm rendering it at a scaled down size of its original (around
>> 1024x768 instead of the 3000px or whatever the orig width is), I don't
>> want the QPainter to have to scale the 3000px -> 1024px every time it
>> paints. So I want to draw the scaled version to a pixmap and cache the
>> pixmap. Great. Works fine.
>>
>> Problem is that if I do that cached pixmap version, the final output
>> looks "block" / pixelated in the final QGraphicsView (since the view may
>> be scaled to fit the target output screen, in this case a 1400x900 at
>> the moment), so the final scene is scaled up a bit. Which results in
>> blocky pixels when using the cached pixmap version.
>>
>> But if I just pass the original 3000px pixmap to the painter and let it
>> do the scaling on the fly, the resulting image is much clearer. (I'm
>> using the painter->drawPixmap(QRect,QPixmap) form of the function to do
>> the scaling).
>>
>> And the sizes are the same - e.g. the size of the QRect that I use when
>> I give it the 3000px image is the same rect size that I use to draw the
>> cached pixmap - so the only explanation I can see for the differing
>> visual outputs is the view transformations.
>>
>> Does anyone have any ideas how to get around that and render "good
>> looking" pixmaps while retaining the speed advantage of caching the
>> scaled pixmaps?
>
> Don't everyone talk at once :-)
>
> In the absence of any responses, I experimented till I was cross-eyed
> and blurry from staring at code. Finally, I came up with a workable
> solution:
>
> QRect viewRect = painter->combinedTransform().mapRect(myRect);
>
> Basically, inside my QGraphicsItem::paint(), I ask the painter what size
> myRect will be when its actually painted.
>
> Then I scale the pixmap that I'm drawing (the really large one,
> remember?) not to myRect.size(), but instead to viewRect.size().
>
> Now, the trick is that when I finally do call painter->drawPixmap(), I
> still give it myRect, not viewRect. That way, drawPixmap() will do the
> same transform on myRect, realize it needs the size I found in viewRect,
> and check the pixmap I gave it - and realize that no scaling is needed!
> Voila - 1:1 scaled, cached pixmaps.
>
> So, it kinda looks like this:
>
>
> QRect myRect = ...;
> QRect viewRect = painter->combinedTransform().mapRect(myRect);
>
> // Not shown here: scale the original pixmap to viewRect.size() and
> cache
>
> painter->drawPixmap(myRect, pixmap);
>
>
> I use QPixmapCache with a key tied to the viewRect.size() to cache the
> results of the scaled pixmap.
>
> Hope that helps someone down the line.
>
> Cheers!
> -josiah
You could also try using
setCacheMode(QGraphicsItem::DeviceCoordinateCache), which should cache
the graphics item in device coordinate and thus do no scaling when
rendering it.
Notice though that using QPixmap::scaled() with Qt::SmoothTransformation
gives higher quality down-scaled versions than drawing the pixmap using
QPainter and QPainter::SmoothPixmapTransform. So you might still want to
do the down-scaling on your own if you want the best quality.
--
Samuel
More information about the Qt-interest-old
mailing list