Page 1 of 1

Transparency and imageData:paste ?

Posted: Mon Jan 21, 2013 10:25 am
by Germanunkol
I need to paste imageData 1 onto another imageData 2, where imageData 1 has transparent parts. Using imageDate2:paste(...) it will replace the part of the image entirely. Instead, I want it to overlay the two (I want it to look the way it looks when using love.graphics.draw() over another love.graphics.draw() call).

I don't want to use Canvases.

So I coded my own function transparentPaste which uses getPixel and setPixel to combine the two:
Simplified, this is what it does for every pixel that overlaps:

Code: Select all

rDest,gDest,bDest,aDest = imgDataDest:getPixel(x,y)
rSource,gSource,bSource,aSource = imgDataSource:getPixel(x-posX,y-posY)
if aSource > 0 then
	rSource,gSource,bSource,aSource = rSource/255,gSource/255,bSource/255,aSource/255
	rDest,gDest,bDest,aDest = rDest/255,gDest/255,bDest/255,aDest/255
	a = aSource + aDest*(1-aSource)
	if a > 0 then
		r = (rSource*aSource+rDest*aDest*(1-aSource))/a
		g = (gSource*aSource+gDest*aDest*(1-aSource))/a
		b = (bSource*aSource+bDest*aDest*(1-aSource))/a
	else
		r,g,b = 0,0,0
	end
			
	r,g,b,a = r*255,g*255,b*255,a*255
	imgDataDest:setPixel(x, y, r, g, b, a)
end
However, this is extremely slow.

Any ideas for a better method without canvases?
Why are programs like the GIMP so fast when doing pretty much exactly the same thing (for example when merging two layers)...

Re: Transparency and imageData:paste ?

Posted: Mon Jan 21, 2013 8:05 pm
by Xgoff
Germanunkol wrote:I need to paste imageData 1 onto another imageData 2, where imageData 1 has transparent parts. Using imageDate2:paste(...) it will replace the part of the image entirely. Instead, I want it to overlay the two (I want it to look the way it looks when using love.graphics.draw() over another love.graphics.draw() call).

I don't want to use Canvases.

So I coded my own function transparentPaste which uses getPixel and setPixel to combine the two:
Simplified, this is what it does for every pixel that overlaps:

Code: Select all

rDest,gDest,bDest,aDest = imgDataDest:getPixel(x,y)
rSource,gSource,bSource,aSource = imgDataSource:getPixel(x-posX,y-posY)
if aSource > 0 then
	rSource,gSource,bSource,aSource = rSource/255,gSource/255,bSource/255,aSource/255
	rDest,gDest,bDest,aDest = rDest/255,gDest/255,bDest/255,aDest/255
	a = aSource + aDest*(1-aSource)
	if a > 0 then
		r = (rSource*aSource+rDest*aDest*(1-aSource))/a
		g = (gSource*aSource+gDest*aDest*(1-aSource))/a
		b = (bSource*aSource+bDest*aDest*(1-aSource))/a
	else
		r,g,b = 0,0,0
	end
			
	r,g,b,a = r*255,g*255,b*255,a*255
	imgDataDest:setPixel(x, y, r, g, b, a)
end
However, this is extremely slow.

Any ideas for a better method without canvases?
Why are programs like the GIMP so fast when doing pretty much exactly the same thing (for example when merging two layers)...
you can attempt mapPixel instead, which might be faster but then again it might not. unfortunately, without canvases, this is really the only way to do it

image editing programs are typically written in C or C++ which by themselves are much faster than lua (luajit could also do this quickly, but not with this style of api). compilers might even be able to use specific optimizations like SIMD which would allow them to perform the same operation on several pixel values at once. additionally, the set/getPixel method love uses is particularly slow since it involves jumping back and forth between C and lua, which is expensive itself.

if love allowed getting/setting pixels via a table rather than individually, these types of operations might actually be somewhat cheap, at least compared to the current method

Re: Transparency and imageData:paste ?

Posted: Tue Jan 22, 2013 3:34 pm
by Germanunkol
I know C-Style Languages are much faster, I just didn't think it was such a large difference.

I doubt mapPixel will be faster -> it will call the function for every pixel, after all, which my function avoids (I did not post this part, but basically, I add lots of smaller map elements - trees, houses, bushes - to a larger image file (the map). So the pasted image is usually much smaller than the large image, and mapPixel would generate way more function calls than needed...?

However, I might try it... maybe I'm wrong and the internal implementation of mapPixel really is much faster than the set/get functions.

Thanks for your reply!