Saving image to .png/.bmp

Pierrou

New member
Joined
Jul 6, 2017
Messages
186
Hi,
Back in the Monkey-X days user Fred (Frédérick Raynal) wrote a module to save images to .bmp files (Mojo1). Does anyone still have this piece of code somewhere? (or something equivalent?)
Thanks!
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
2,815
@JaviCervera 's framework Vortex includes a FontTool which can save to PNG files at least. If no one is coming up with a monkey module, maybe try to study the source and adapt things you need.
 

Pierrou

New member
Joined
Jul 6, 2017
Messages
186
Thanks Mike! Looks quite complicated (C++ and stuff) to me :oops::oops::)
I could do without saving pics but being able to get screenshots would be quite useful to me.
 

wick

Member
3rd Party Module Dev
Tutorial Author
Patreon Bronze
Joined
Jul 17, 2017
Messages
69
Hey @Pierrou! I modified it before the forums went down to work with mojo2, I hope it might be helpful for you?

Code:
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

Usage:

In my user input:
Code:
if KeyHit(KEY_F8) Then takeScreenshot = True

In my main draw method (using a mojo2 canvas):
Code:
If takeScreenshot
    screenshot = New mojo2.Image(screenwid, screenhet, .5, .5)
    canvas.SetRenderTarget(screenshot)
EndIf



'< draw everything you want to be in the screenshot >


If screenshot <> Null
    local screenshotcanvas:= New Canvas()
    screenshotcanvas.Clear(0.0, 0.0, 0.0)
    screenshotcanvas.DrawImage(screenshot, screenwid/2, screenhet/2)
              
    'save the screenshot
    Local bmp:= New BmpFile()
    bmp.Create(screenshotcanvas)
    bmp.Save("testscreenshot")
      
    canvas.SetRenderTarget(Null)

    screenshot = Null
    takeScreenshot = False
EndIf
 

wick

Member
3rd Party Module Dev
Tutorial Author
Patreon Bronze
Joined
Jul 17, 2017
Messages
69
Another option for PNG is in the Regal module, but I ran into the same problem that it was too complicated for me to figure out.
 

Pierrou

New member
Joined
Jul 6, 2017
Messages
186
Thanks a lot Wick! Tied to Mojo1/IgnitionX for my current project but very useful thanks. I forgot about the Regal module, will try to use it.
 

wick

Member
3rd Party Module Dev
Tutorial Author
Patreon Bronze
Joined
Jul 17, 2017
Messages
69
Top Bottom