That time of the day again...

Patrick Julien freak at codepimps.org
Fri Oct 10 21:18:59 CEST 2003


On October 10, 2003 11:23 am, Boudewijn Rempt wrote:
> An alternative way of painting, more like the gimp. First create a small
> empty, transparent, layer -- really small, you can see how small because of
> an amusing glitch that I don't have time to look into now), then paint the
> pixels on that layer, and composite it with the real image. In theory,
> because I use the bitblt that knows about tiles to composite the image,
> undo/redo should be possible, but it isn't yet.
>
> Oh well, time for a beer and dinner.

>
> ---------------------------------------------------------------------------
>--- QRect r = polyline.boundingRect();
>
>     if ( r.left() < 0 ) r.setLeft( 1 );
>     if ( r.bottom() < 0 ) r.setBottom( 1 );
>     if ( r.right() < 0 ) r.setRight( 1 );
>     if ( r.top() < 0 ) r.setTop( 1 );
>
>     if ( r.left() >= m_device->width() ) r.setLeft( m_device->width() - 1);
>     if ( r.bottom() >= m_device->height() ) r.setBottom( 
> m_device->height() - 1);
>     if ( r.right() >= m_device->width() ) r.setRight( m_device->width() -
> 1); if ( r.top() >= m_device->height() ) r.setTop( m_device->height() - 1);
>
>     // XXX: should paint a single dot
>     if ( r.left() == r.right() && r.top() == r.bottom() ) return;
>
> if ( 1 ) {
>     // Create a layer the size of the dab
>     KisLayerSP layer = new KisLayer( m_device->image(),
>                                      r.width(), r.height(),
>                                      "dab",
>                                      OPACITY_TRANSPARENT);
>
>     KisTileMgrSP tileMgr = layer -> data();
>
>     // If that succeeded, fill it with transparent black pixels
>     if ( layer ) {
>         layer -> visible( false );
>         KisPainter gc( layer.data() );

God do I hate having to call data() on KSharedPtr ;(




>         gc.fillRect( 0,  0,
>                      layer->width(),  layer->height(),
>                      KoColor::black(),
>                      OPACITY_TRANSPARENT );
>         gc.end();

Again, gc.end() here is optional.

>     }
>
>     // Construct a PixelData structure
>     KisPixelDataSP pd = new KisPixelData;
>
>     pd -> mgr = 0;
>     pd -> tile = 0;
>     pd -> mode = TILEMODE_READ;
>     pd -> x1 = 0;
>     pd -> x2 = r.width() - 1;
>     pd -> y1 = 0;
>     pd -> y2 = r.height() - 1;
>     pd -> width = pd -> x2 - pd -> x1 + 1;
>     pd -> height = pd -> y2 - pd -> y1 + 1;
>     pd -> depth = tileMgr -> depth();
>     pd -> stride = pd -> depth * pd -> width;
>     pd -> owner = false;
>
>     // Read the blank pixels from the dab layer into the pixeldata
>     // Assumes RGBA
>     pd -> data = new QUANTUM[pd->width * pd->height * 4];
>     tileMgr -> readPixelData(pd);

If you know you're going to squish everything, just specify the TILEMODE_WRITE 
only flag, this will cause data to *NOT* be read in from the paint device 
itself.  Just use KisTileMgr::pixelData() and not readPixelData() directly.

If fact, I'm suprised I left the read stuff public.

>
>     // Convert to a QImage. This assumes RGBA
>     QImage img = QImage(pd -> data,
>                         r.width(), r.height(),
>                         layer -> data() -> depth() * CHAR_BIT,
>                         0, 0,
>                         QImage::LittleEndian);
>
>     // Create a QPixmap -- i.e. a Qt paintdevice, because Trolltech
>     // has done all the Foley & Dam, Newman & Sproull and Hearn reading
>     // for us and done the graphics primitives that I'm too lazy to
>     // code.
>     QPixmap buffer = QPixmap( img );

Yeah, well,  I've now told you the performance difference of using not the 
tiles directly, but at the same time, there is still that we can do here even 
without tiles.  Unless I'm mistaken here, you are simply have a pixmap 
(buffer variable) that is completely fill with black transparent.

We can draw (fillRect) on a pixmap much faster that we can on tiles.  You 
could start directly with your pixmap.

Then you can use the TILEMODE_WRITE flag to overwrite, i.e. not read the 
current paint device in.


>
>     QPainter p;
>     p.begin(&buffer);
>     p.translate( -r.x(),  -r.y() );
>     // Get currently selected brush or pattern, color and use
>     // that as the pen
>     p.drawPolyline( polyline, index, npoints );
>     p.end();
>
>     // Convert back to a QImage. Hope nothing bad happened to the alpha
>     img = buffer.convertToImage();
>
>     // Back into the pixeldata
>     pd-> data = img.bits();

Actually, again, the pointer is already set to the same address, i.e. the 
image we're initialize with pd -> data, don't forget you newup pd -> data, 
KisPixelData dtor will delete it correctly, but this makes your intent harder 
to understand.  It doesn't put them back after all, it's exactly the same 
buffer you passed in to QImage in the constructor call...

If it weren't, you would be losing that pointer and leaking that memory.


>
>     // And back into the layer
>     layer -> data() -> writePixelData( pd );

Hmm, is this code you want to add to KisPainter BTW?  If it's not, I'm not 
sure it's a good idea to access the KisTileMgr directly from the outside.


>
>     // Composite the layer on the image. This is undo/redo-able.
>     bitBlt( r.x(),  r.y(), COMPOSITE_OVER, layer.data(), OPACITY_OPAQUE );
>
> -


So I guess you are doing this from KisPaintDevice proper, you should probably 
keep this in KisPainter.





More information about the kimageshop mailing list