RosettaCodeData/Task/Image-noise/F-Sharp/image-noise.fs
2023-07-01 13:44:08 -04:00

73 lines
2.7 KiB
FSharp

open System.Windows.Forms
open System.Drawing
open System.Drawing.Imaging
open System.Runtime.InteropServices
open System.Diagnostics
open Microsoft.FSharp.NativeInterop
#nowarn "9"
let rnd = System.Random()
// Draw pixels using unsafe native pointer accessor.
// This updates the bitmap as fast as possible.
let drawbits_fast (size:int) (bits:BitmapData) =
let mutable (p:nativeptr<byte>) = NativePtr.ofNativeInt(bits.Scan0)
for n = 0 to size-1 do
let c = rnd.Next(2) * 255
NativePtr.set p 2 (byte c)
NativePtr.set p 1 (byte c)
NativePtr.set p 0 (byte c)
NativePtr.set p 3 (byte 255)
p <- NativePtr.add p 4
// A reasonably efficient updater using marshalling to copy an array of generated
// integers onto the managed bitmap pixel data (see the C# example as well).
let drawbits_safe (size:int) (bits:BitmapData) =
let data = Array.init size (fun n ->
let c = rnd.Next(2) * 255
0xff000000 ||| (c <<< 16) ||| (c <<< 8) ||| c)
Marshal.Copy(data, 0, bits.Scan0, size) |> ignore
// Create a new bitmap and update using the specified function
let make_image (width:int) (height:int) f =
let size = width * height
let bmp = new Bitmap(width, height)
let bits = bmp.LockBits(Rectangle(0,0,width,height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)
f size bits
bmp.UnlockBits(bits)
bmp
// Draw 30 frames and record the time and display the frames per second
// This function is run asynchronously to avoid blocking the main GUI thread.
let drawImage (box:PictureBox) (label:Label) f = async {
while true do
let timer = new Stopwatch()
timer.Start()
for frames = 0 to 29 do
let bmp = make_image 320 240 f
box.Image <- bmp
timer.Stop()
let fps = 30000. / timer.Elapsed.TotalMilliseconds
label.Text <- sprintf "%.1f fps" fps }
[<System.STAThread>]
[<EntryPoint>]
let main args =
let form = new Form(AutoSize=true,
Size=new Size(0,0),
Text="image noise demo")
let panel = new FlowLayoutPanel(AutoSize=true,FlowDirection=FlowDirection.TopDown)
let box = new PictureBox(AutoSize=true)
let label = new Label(AutoSize=true, Text="Ready")
form.FormClosed.Add(fun eventArgs -> Async.CancelDefaultToken()
Application.Exit())
form.Controls.Add(panel)
panel.Controls.Add(box)
panel.Controls.Add(label)
if args.Length > 0 && args.[0] = "-safe" then
drawImage box label drawbits_safe |> Async.Start
else
drawImage box label drawbits_fast |> Async.Start
form.Show()
Application.Run()
0