combining 2 pixmaps, including alpha

BlitzMax Forums/BlitzMax Programming/combining 2 pixmaps, including alpha

skn3(Posted 2006) [#1]
Any advice?

I know the general idea about merging the seperate channels, but my brain is asleep! So anyone who knows or has done it before, care to give some help ?

Just simply need the algorithm for combining two argb values. Taking into account the alpha as well as rgb.


Dreamora(Posted 2006) [#2]
There is no basic algorithm.
It depends on which mixing behavior you want to have.

There is additive, multiplicative, alpha based, 1 - alpha based etc etc


skn3(Posted 2006) [#3]
Alpha based. I am just taking 3 seperate png images, with alpha, and I want to combine them all ontop of one another while preserving the alpha layer.


Dreamora(Posted 2006) [#4]
In that case, one possibility would be (on a per pixel base):

colorRGB = colorRGB1 * alpha1/255.0 + colorRGB2 * alpha2/255.0
colorAlpha = (alpha1 + alpha2)/2.0

A different approcha is the 1 minus alpha that is used by BMs alphablend. (mixing by colorRGB1 * alpha1/255.0 + colorRGB2 * (255-alpha1)/255.0 ) but that does not preserve alpha as it mixes the color basing on the first (overlay) images alpha.

Problem I see (or at least do not seem to understand) is the preserve alpha layer.
There are 2 reasons for that:

1. Alpha is no layer but a color like Red Green and Blue
2. If both images have alpha, which ones alpha do you want to preserve?


skn3(Posted 2006) [#5]
Basically Im writting a small command line app for somone. It just lets you pass X number of images to it, and they will be combined into one.

Both will have alpha, so it is going to combine them. If both have alpha it will merge accordingly. I guess blend the colors based on their alpha and add the 2 alpha values together.


skidracer(Posted 2006) [#6]
add the 2 alpha values together


Two semi transparent surfaces don't make an opaque surface just a slightly less transparant surface. You also need to blend each colors contribution to the final color based on the ratio of the two alphas I think.


Dreamora(Posted 2006) [#7]
Your desire sounds like the first equation I've listed with combining the color alpha based and "averageing" the alpha of both (which does preserve the alpha if both had the same)

To do this, you can or better must use pixmaps btw, not TImage as pixelaccess is only possible on them.


skn3(Posted 2006) [#8]
Thanks both of you. Yeah I am using pixmaps. I had a basic program working, just it wasn't working quite right. Lol. Just got back from being out of town so I will have a play later and post the results.

Thanks


skn3(Posted 2006) [#9]
The finished product. I found a working formula on the apple site.

http://www.devworld.apple.com/documentation/Performance/Conceptual/vImage/Chapter8/chapter_8_section_3.html

SuperStrict

Framework BRL.LinkedList
Import BRL.Pixmap
Import BRL.PNGLoader
Import BRL.StandardIO

'output.png 46 46 tile.png 0 0 letter.png 0 0 score.png 92 0
'output.png 30 30 test1.png 0 0 test2.png 0 0

Type ttilemaker
	Field pixmap:tpixmap
	Field output:String
	Field width:Int
	Field height:Int
	Field layers:tlist = CreateList()
	
	Method Save()
		Local array:Int[,,]
		Local layer:tlayer
		
		For layer = EachIn layers
			If array = Null
				array = PixmapToPixelArray(layer.pixmap,layer.x,layer.y)
			Else
				CombinePixelArrays(array,PixmapToPixelArray(layer.pixmap,layer.x,layer.y))
			End If
		Next

		SavePixelArray(array,output)
	End Method
	
	Method PixmapToPixelArray:Int[,,](pixmap:tpixmap,offsetx:Int=0,offsety:Int=0)
		Local x:Int
		Local y:Int
		Local array:Int[width,height,4]
		Local pixel:Int
		
		For y = 0 Until height
			For x = 0 Until width
				pixel = ReadPixel(pixmap,x+offsetx,y+offsety)
				
				array[x,y,0] = GetA(pixel)
				array[x,y,1] = GetR(pixel)
				array[x,y,2] = GetG(pixel)
				array[x,y,3] = GetB(pixel)
			Next
		Next
		
		Return array
	End Method
	
	Method CombinePixelArrays:Int[,,](bottom:Int[,,],top:Int[,,])
		'this function will take 2 pixel arrays [x,y,rgba] and combine them.
		Local x:Int
		Local y:Int
		Local a:Float
		Local r:Float
		Local g:Float
		Local b:Float
		
		For y = 0 Until height
			For x = 0 Until width
				If top[x,y,0] = 255
					a = 255
					r = top[x,y,1]
					g = top[x,y,2]
					b = top[x,y,3]
				ElseIf top[x,y,0] = 0
					a = bottom[x,y,0]
					r = bottom[x,y,1]
					g = bottom[x,y,2]
					b = bottom[x,y,3]
				Else
					a = (top[x,y,0] * 255 + (255 - top[x,y,0]) * bottom[x,y,0] + 127) / 255
					r = (top[x,y,0] * top[x,y,1] + (((255 - top[x,y,0]) * bottom[x,y,0] + 127) / 255) * bottom[x,y,1] + 127) / a
					g = (top[x,y,0] * top[x,y,2] + (((255 - top[x,y,0]) * bottom[x,y,0] + 127) / 255) * bottom[x,y,2] + 127) / a
					b = (top[x,y,0] * top[x,y,3] + (((255 - top[x,y,0]) * bottom[x,y,0] + 127) / 255) * bottom[x,y,3] + 127) / a
				End If
				bottom[x,y,0] = a
				bottom[x,y,1] = r
				bottom[x,y,2] = g
				bottom[x,y,3] = b
			Next
		Next
	End Method
	
	Method SavePixelArray:Int(array:Int[,,],url:Object)
		Local x:Int
		Local y:Int
		Local savepixmap:tpixmap = CreatePixmap(width,height,PF_BGRA8888)
		
		For y = 0 Until height
			For x = 0 Until width
				WritePixel(savepixmap,x,y,GetRGBA(array[x,y,1],array[x,y,2],array[x,y,3],array[x,y,0]))
			Next
		Next
		
		SavePixmapPNG(savepixmap,url)
	End Method
	
	Method GetRGBA:Int(r:Int,g:Int,b:Int,a:Int=255)
		Return r | (g Shl 8) | (b Shl 16) | (a Shl 24)
	End Method
	
	Method GetA:Int(argb:Int)
		Return argb Shr 24 & %11111111
	End Method
	
	Method GetR:Int(argb:Int)
		Return argb & %11111111
	End Method
	
	Method GetG:Int(argb:Int)
		Return argb Shr 8 & %11111111
	End Method
	
	Method GetB:Int(argb:Int)
		Return argb Shr 16 & %11111111
	End Method
End Type

Function CreateTileMaker:ttilemaker()
	If appargs.length < 5 Return Null
	
	Local tilemaker:ttilemaker = New ttilemaker
	
	tilemaker.output = AppArgs[1]
	tilemaker.width = AppArgs[2].toint()
	tilemaker.height = AppArgs[3].toint()
	
	Local arg:Int = 4
	Local layer:tlayer
	
	While arg <= appargs.length - 3
		layer = New tlayer
		layer.pixmap = LoadPixmapPNG(AppArgs[arg])
		If layer.pixmap = Null Return Null
		layer.x = AppArgs[arg+1].toint()
		layer.y = AppArgs[arg+2].toint()
		tilemaker.layers.addlast(layer)
		arg:+3
	Wend
	
	tilemaker.pixmap = CreatePixmap(tilemaker.width,tilemaker.height,PF_BGRA8888)
	
	Return tilemaker
End Function

Type tlayer
	Field pixmap:tpixmap
	Field x:Int
	Field y:Int
End Type


'-----------------------------------------------------
Local tilemaker:ttilemaker = CreateTileMaker()

If tilemaker <> Null
	tilemaker.Save()
	Print "RESULT=1"
Else
	Print "RESULT=0"
End If



tonyg(Posted 2006) [#10]
What does this do differently , or how much quicker is this, than drawing the images with alpha and using grabpixmap?


skn3(Posted 2006) [#11]
It means you dont have to use dx or gl. It will combine the images, and keep alpha layers intact. Grabpixmap cant do that, it can only grab the blended image with no alpha layer. (i think )