BMP file save for GLFW - updated for mojo2

Monkey Targets Forums/Desktop/BMP file save for GLFW - updated for mojo2

wick(Posted April) [#1]
Heya, I couldn't find an easy way to save images in mojo2, so I've tweaked Fred's code from here to take a mojo2 canvas (instead of screen coordinates) and turn it into a bmp file:

Strict
'modified from Fred's code at monkey-x.com/Community/posts.php?topic=5528

Import mojo2
Import brl

Class	BmpFile

	Field	Width:Int  			' bmp image width
	Field	Height:Int			' bmp image height
	
	Field	Pixels:Int[1]		' array for screen Pixels
	Field 	PixelDataBuffer:DataBuffer

	Field	FileSize:Int		' bmp file size
	Field	Buffer:DataBuffer	' bmp file PixelDataBuffer (header + Pixels)

	Field	PadLineWidth:Int	' bmp real line size
	
	' default header for 24bpp image
	Field	Header:Int[] = [ $42,$4D,$D6,$83,$00,$00,$00,$00,$00,$00,$36,$00,$00,$00,$28,$00,$00,$00,$6C,$00,$00,$00,$68,$00,$00,
		$00,$01,$00,$18,$00,$00,$00,$00,$00,$00,$00,$00,$00,$C3,$0E,$00,$00,$C3,$0E,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ]
	Const	FILE_SIZE		:=	$2
	Const	IMAGE_WIDTH		:=	$12
	Const	IMAGE_HEIGHT	:=	$16
	Const	RAW_DATA_SIZE	:=	$22

	Method Create:Void(canvas:Canvas)	' Call within OnRender after drawing the image to grab
		Width = canvas.Width
		Height = canvas.Height
		PadLineWidth = (((Width*3) + 3) / 4) * 4		'to get each line to end on a multiple of 4; req for .bmp format
		
		'get the pixel data, convert it to an int array
		PixelDataBuffer = New DataBuffer(Width*Height*4)
		canvas.ReadPixels(0,0,Width,Height, PixelDataBuffer)
		Pixels = Pixels.Resize(Width*Height*4)
		PixelDataBuffer.PeekBytes(0, Pixels)
		
		'set up the file (3 channels only; no transparency)
		FileSize = Header.Length() + PadLineWidth * Height * 3
		Buffer = New DataBuffer( FileSize )
		
		'write the header information
		local ptr:Int
		for ptr = 0 until Header.Length
			Buffer.PokeByte ptr, Header[ptr]
		next
		Buffer.PokeInt FILE_SIZE, FileSize
		Buffer.PokeInt IMAGE_WIDTH, Width
		Buffer.PokeInt IMAGE_HEIGHT, Height
		Buffer.PokeInt RAW_DATA_SIZE, PadLineWidth * Height
		
		'write to the databuffer that we'll eventually save as a .bmp
		local i:Int = 0
		local pix:= New Int[4]
		for local ys:Int = Height-1 to 0 Step -1
			ptr = (Height - ys - 1) * PadLineWidth + Header.Length
			for local xs:Int = 0 until Width
			
				For Local channel:Int = 0 to 2' R G B (omit A)
					pix[channel] = Pixels[i+channel]
				Next
				
				Buffer.PokeByte ptr+0, pix[2] & $ff   'B
				Buffer.PokeByte ptr+1, pix[1] & $ff   'G
				Buffer.PokeByte ptr+2, pix[0] & $ff   'R

				'update where we're writing to
				ptr += 3
				'update where we're reading from
				i += 4
			next
		next
		
	End
	  
	Method	Save:Void( filename:String )	' filename without .bmp

		Local file:=FileStream.Open( "monkey://internal/"+filename+".bmp","w" )
		If file
			file.Write Buffer, 0, FileSize
			file.Close
		Endif
		
	End
	
End


I also saw this thread that apparently is the key to saving pngs, but was too confused to really know where to start. Hopefully this'll be useful for people looking for a plug-and-play option.

(since it's a bmp, there's no transparency and it's uncompressed)


Pierrou(Posted April) [#2]
Hi,
I've been dreaming of this!! Can't wait to try it thanks a lot!