Repository: mxgmn/MarkovJunior
File: source/Graphics.cs (C#)

Code before:
﻿// Copyright (C) 2022 Maxim Gumin, The MIT License (MIT)

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;

static class Graphics
{
    public static (int[], int, int, int) LoadBitmap(string filename)
    {
        try
        {
            Bitmap bitmap = new(filename);
            int width = bitmap.Width, height = bitmap.Height;
            var bits = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            int[] result = new int[bitmap.Width * bitmap.Height];
            System.Runtime.InteropServices.Marshal.Copy(bits.Scan0, result, 0, result.Length);
            bitmap.UnlockBits(bits);
            bitmap.Dispose();
            return (result, width, height, 1);
        }
        catch (Exception) { return (null, -1, -1, -1); }
    }

    public static void SaveBitmap(int[] data, int width, int height, string filename)
    {
        Bitmap result = new(width, height);
        var bits = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
        System.Runtime.InteropServices.Marshal.Copy(data, 0, bits.Scan0, data.Length);
        result.UnlockBits(bits);
        result.Save(filename);
    }

    public static (int[], int, int) Render(byte[] state, int MX, int MY, int MZ, int[] colors, int pixelsize, int MARGIN) => MZ == 1 ? BitmapRender(state, MX, MY, colors, pixelsize, MARGIN) : IsometricRender(state, MX, MY, MZ, colors, pixelsize, MARGIN);

    public static (int[], int, int) BitmapRender(byte[] state, int MX, int MY, int[] colors, int pixelsize, int MARGIN)
    {
        int WIDTH = MARGIN + MX * pixelsize, HEIGHT = MY * pixelsize;
        int TOTALWIDTH = WIDTH, TOTALHEIGHT = HEIGHT;
        //int TOTALWIDTH = 189 + MARGIN, TOTALHEIGHT = 189;
        int[] bitmap = new int[TOTALWIDTH * TOTALHEIGHT];
        for (int i = 0; i < bitmap.Length; i++) bitmap[i] = GUI.BACKGROUND;
        //for (int i = 0; i < bitmap.Length; i++) bitmap[i] = 255 << 24;

        int DX = (TOTALWIDTH - WIDTH) / 2;
        int DY = (TOTALHEIGHT - HEIGHT) / 2;

        for (int y = 0; y < MY; y++) for (int x = 0; x < MX; x++)
            {
                int c = colors[state[x + y * MX]];

Review comment (suggestion):
You can use a `using` to avoid the explicit call to `Dispose`.
But most importantly, you can vectorize all this with the built-in API to copy the pixel buffer:
```suggestion
            using var image = Image.Load<Bgra32>(filename);

            int width = image.Width;
            int height = image.Height;
            int[] result = new int[width * height];

            image.CopyPixelDataTo(MemoryMarshal.Cast<int, Bgra32>(result));
```

Code after:
﻿// Copyright (C) 2022 Maxim Gumin, The MIT License (MIT)

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

static class Graphics
{
    public static (int[], int, int, int) LoadBitmap(string filename)
    {
        try
        {
            var image = Image.Load<Bgra32>(filename);
            int width = image.Width, height = image.Height;
            var result = new int[width * height];
            for (var j = 0; j < height; j += 1)
            {
                for (var i = 0; i < width; i += 1)
                {
                    result[j * width + i] = unchecked((int) image[i, j].Bgra);
                }
            }

            image.Dispose();
            return (result, width, height, 1);
        }
        catch (Exception)
        {
            return (null, -1, -1, -1);
        }
    }

    public static void SaveBitmap(int[] data, int width, int height, string filename)
    {
        var formattedData = new Bgra32[data.Length];
        for (var i = 0; i < data.Length; i += 1)
        {
            formattedData[i] = new Bgra32
            {
                Bgra = unchecked((uint) data[i])
            };
        }

        var image = Image.WrapMemory(Configuration.Default, new Memory<Bgra32>(formattedData), width, height);
        image.SaveAsPng(filename);
        image.Dispose();
    }

    public static (int[], int, int) Render(byte[] state, int MX, int MY, int MZ, int[] colors, int pixelsize, int MARGIN) => MZ == 1 ? BitmapRender(state, MX, MY, colors, pixelsize, MARGIN) : IsometricRender(state, MX, MY, MZ, colors, pixelsize, MARGIN);