Cropping paint devices

Adrian adrian at pagenet.plus.com
Sat Mar 26 14:55:17 CET 2005


On Sat Mar 26 14:08 , Boudewijn Rempt <boud at valdyas.org> sent:

>On Saturday 26 March 2005 13:50, Casper Boemann wrote:
>
>> When you create the tileRect you must multiply width to col and height to
>
>> row.

I think there's a bit more to it because the tiles in each hash table entry are
stored in a linked list:

> void KisTiledDataManager::setExtent(Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h)
> {
> 	QRect newRect = QRect(x, y, w, h).normalize();
> 	QRect oldRect = QRect(m_extentMinX, m_extentMinY, m_extentMaxX - m_extentMinX
+ 1, m_extentMaxY - m_extentMinY + 1).normalize();
> 
> 	// Do nothing if the desired size is bigger than we currently are: that is
handled by the autoextending automatically
> 	if (newRect.contains(oldRect)) return;
> 
> 	// Loop through all tiles, if a tile is wholly outside the extent, add to the
memento, then delete it,
> 	// if the tile is partially outside the extent, clear the outside pixels to
black transparent (XXX: use the
> 	// default pixel for this when avaiable).
> 	for(int i = 0; i < 1024; i++)
> 	{
> 		KisTile *tile = m_hashTable[i];
> 

In order to remove deleted tiles from the hash table list, you need to keep track
of the tile before the one to be deleted.

KisTile *prevTile = 0;

> 		while(tile)
> 		{
> 			QRect tileRect = QRect(tile -> getCol(), tile -> getRow(), KisTile::WIDTH,
KisTile::HEIGHT);

This wants to be:

QRect tileRect = QRect(tile -> getCol() * KisTile::WIDTH, tile -> getRow() *
KisTile::HEIGHT, KisTile::WIDTH, KisTile::HEIGHT);

> 
> 			
> 			if (newRect.contains(tileRect)) {
> 				// Completely inside, do nothing
> 				tile->getNext();

This should be:

prevTile = tile;
tile = tile->getNext();

> 			}
> 			else {
> 				Q_UINT32 tileHash = calcTileHash(tileRect.x(), tileRect.y());

i is the tileHash for this tile so you can replace tileHash with i:

ensureTileMementoed(tile -> getCol(), tile -> getRow(), i, tile);

> 			
> 				if (newRect.intersects(tileRect)) {
> 					// Partially inside, clear the non-intersecting bits
> 
> 					// Create the intersection of the tile and new rect
> 					QRect intersection = newRect.intersect(tileRect);
> 					intersection.setRect(intersection.x() - tileRect.x(), intersection.y() -
tileRect.y(), intersection.width(), intersection.height());
> 
> 					// This can be done a lot more efficiently, no doubt, by clearing runs of
pixels to the left and the right of
> 					// the intersecting line.
> 					for (int y = 0; y < KisTile::HEIGHT; ++y) {
> 						for (int x = 0; x < KisTile::WIDTH; ++x) {
> 							if (!intersection.contains(x,y)) {
> 								Q_UINT8 * ptr = tile -> data(x, y);
> 								memset(ptr, 0, m_pixelSize);
> 							}
> 						}
> 					}
> 					
> 					tile->getNext();

This should be:

prevTile = tile;
tile = tile->getNext();

> 				}
> 				else {
> 					// Completely outside, delete this tile. It had already been mementoed
> 					KisTile *deltile = tile;

You need to remove the deleted tile from the hash table list before deleting it:

if (prevTile == 0) {
	// This was the first tile in the hash table bucket
	m_hashTable[i] = tile -> getNext();
} else {
	prevTile -> setNext(tile -> getNext());
}

tile = tile->getNext();
delete deltile;

> 				}
> 			}
> 			
> 
> 		}
> 	}
> 	
> 	// Set the extent correctly
> 	m_extentMinX = x;
> 	m_extentMinY = y;
> 	m_extentMaxX = x + w + 1;
> 	m_extentMaxY = y + h + 1;

These should both be - 1 rather than + 1.

Adrian



More information about the kimageshop mailing list