[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