MultiplyImage Function

Monkey Forums/Monkey Code/MultiplyImage Function

skid(Posted 2014) [#1]
This code was re-factored from inside my current project where it generates colored versions of bitmap font images to avoid the SetColor DrawImage penalty in html5.

[edit] tested and fixed code x 2

[edit2] changed white pass to to additive


' processimage.monkey
' 
' the beginnings of an image processing toolkit for monkey
'
' images can ONLY be processed 
'   once they are fully loaded
'   from inside an OnRender handler
'
' a Cls command should be used after processing any images

Strict

Import mojo

Function Main%()
	New TestProcess()
	Return 0
End


Class TestProcess Extends App

	Field font:Image
	Field redfont:Image

	Method OnCreate%()
		font=LoadImage("motorwerk.png")
		Return 0
	End
	
	Method OnRender%()
	
		If Not redfont
			redfont=MultiplyImage(font,$ff0000)		
		Endif
		
		Cls
		DrawImage redfont,0,0
		Return 0
	End
	
End


Function MultiplyImage:Image( image:Image,rgb% )
	Return ProcessImage( image,New MultiplyPixel(rgb) )
End

Interface PixelProcessor
	Method ProcessPixel%( argb% )
End

Class MultiplyPixel Implements PixelProcessor

	Field factor%
	
	Method New(rgb%)
		factor=rgb
	End

	Method ProcessPixel%(argb%)
		Local a24%=argb & $ff000000
		Local r16%=((((argb Shr 16)&$FF)*((factor Shr 16)&$FF))Shr 8)Shl 16
		Local g8%=((((argb Shr 8)&$FF)*((factor Shr 8)&$FF))Shr 8)Shl 8
		Local b0%=((((argb)&$FF)*((factor)&$FF))Shr 8)
		Return a24|r16|g8|b0
	End

End

' batch convert image by reading display size tiles of pixels
' does two pass, white is for color and black is for mask
' write result of callback processing to black 
' return result in new image

Function ProcessImage:Image(image:Image,pixelproc:PixelProcessor)		
	Local width%=image.Width()
	Local height%=image.Height()
			
	Local stepw%=DeviceWidth()
	Local steph%=DeviceHeight()
	
	If stepw>width stepw=width
	If steph>height steph=height		
	
	Local black:=New Int[width*height]
	Local white:=New Int[width*height]
	
	Local x%=0
	Local y%=0
	While y<height
		Local h%=height-y
		If h>steph h=steph
		While x<width
			Local w%=width-x
			If w>stepw w=stepw				
			
			Cls 255,255,255
			SetColor 0,0,0
			DrawImage image,-x,-y	
	
			ReadPixels(black,0,0,w,h,y*width+x,width)
	
			Cls 0,0,0
			SetBlend AdditiveBlend
			SetColor 255,255,255
			DrawImage image,-x,-y
			SetBlend AlphaBlend
	
			ReadPixels(white,0,0,w,h,y*width+x,width)				
			
			x+=stepw				
		Wend
		y+=steph
		x=0
	Wend

	Local n%=width*height
	For Local i%=0 Until n
		Local a%=255-(black[i] & $ff)
		Local rgb%=white[i] & $ffffff
		Local rgba%=(a Shl 24) | rgb
		black[i]=pixelproc.ProcessPixel(rgba)
	Next
	
	Local mult:=CreateImage(width,height)
	mult.WritePixels black,0,0,width,height		
	Return mult
End
	



Nobuyuki(Posted 2014) [#2]
not bad! To note, this still has all the same limitations that come with ReadPixels (no alpha), plus a small penalty for producing the bitmap, of course. IIRC, Android has some slowness with colored images too, so baking a bitmap there could also be beneficial. In the case of Android, since it's an ogl target, you can also replace readpixels with GetImageData from gles11 and regain the alpha support.


skid(Posted 2014) [#3]
It uses white black sampling which should solve the alpha problem.

Actually there is possibly a problem with the rgb which my recent change to additive has probably not solved.

It's likely I need extra code as my ARGB input is I think now pre-multiplied alpha (darker the more transparent the src).

Monkey should probably if it's not already be using pre-multiplied pixel format internally as it is best practice on a lot of EGL chipsets but the Read and Write pixel commands should logically be using plain ARGB so version 3 here we go...

TBC