{"id":48,"date":"2020-06-06T08:12:58","date_gmt":"2020-06-06T08:12:58","guid":{"rendered":"https:\/\/michaeljohnsteiner.com\/?p=48"},"modified":"2020-06-06T08:12:58","modified_gmt":"2020-06-06T08:12:58","slug":"memorybitmap-cs","status":"publish","type":"post","link":"https:\/\/michaeljohnsteiner.com\/index.php\/2020\/06\/06\/memorybitmap-cs\/","title":{"rendered":"MemoryBitmap.cs"},"content":{"rendered":"\n<p>Direct Access Pixel Data, GetPixel, SetPixel<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">using System;\nusing System.Drawing;\nusing System.Drawing.Imaging;\nusing System.IO;\npublic unsafe class MemoryBitmap : IDisposable\n{\n    private readonly BitmapData _bmpData;\n    private readonly int        _depth;\n    private readonly byte*      _pfp;\n    private readonly int        _stride;\n    private          Bitmap     _memoryBitmap;\n    public MemoryBitmap(string path)\n    {\n        if (path.IsNullOrEmpty())\n            throw new Exception(\"Path cannot be null or empty.\");\n        if (!File.Exists(path))\n            throw new Exception($\"Path {path} does not exist.\");\n        var bitmap = new Bitmap(path);\n        _memoryBitmap = bitmap;\n        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb &amp;&amp; _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb &amp;&amp; _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)\n        {\n            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);\n            using (var gr = Graphics.FromImage(clone))\n            {\n                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));\n                _memoryBitmap = clone;\n            }\n        }\n        Width  = _memoryBitmap.Width;\n        Height = _memoryBitmap.Height;\n        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);\n        try\n        {\n            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);\n        }\n        catch (Exception ex)\n        {\n            throw new Exception(\"Could not lock bitmap\", ex.InnerException);\n        }\n        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) \/ 8;\n        _pfp    = (byte*) _bmpData.Scan0.ToPointer();\n        _stride = _bmpData.Stride;\n    }\n    public MemoryBitmap(Bitmap bitmap)\n    {\n        _memoryBitmap = bitmap ?? throw new Exception(\"Bitmap cannot be null\");\n        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb &amp;&amp; _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb &amp;&amp; _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)\n        {\n            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);\n            using (var gr = Graphics.FromImage(clone))\n            {\n                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));\n                _memoryBitmap = clone;\n            }\n        }\n        Width  = _memoryBitmap.Width;\n        Height = _memoryBitmap.Height;\n        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);\n        try\n        {\n            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);\n        }\n        catch (Exception ex)\n        {\n            throw new Exception(\"Could not lock bitmap\", ex.InnerException);\n        }\n        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) \/ 8;\n        _pfp    = (byte*) _bmpData.Scan0.ToPointer();\n        _stride = _bmpData.Stride;\n    }\n    public int Width\n    {\n        get;\n    }\n    public int Height\n    {\n        get;\n    }\n    public void Dispose()\n    {\n        Dispose(true);\n        GC.SuppressFinalize(this);\n    }\n    public void ConvertFormat(PixelFormat newPf)\n    {\n        var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, newPf);\n        using (var gr = Graphics.FromImage(clone))\n        {\n            gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));\n            _memoryBitmap = clone;\n        }\n    }\n    public void Save(string path)\n    {\n        _memoryBitmap.Save(path);\n    }\n    protected virtual void Dispose(bool disposing)\n    {\n        if (!disposing)\n            return;\n        if (_memoryBitmap != null)\n            _memoryBitmap.UnlockBits(_bmpData);\n    }\n    private byte* PixelPointer(int x, int y)\n    {\n        return _pfp + y * _stride + x * _depth;\n    }\n    public Color GetPixel(int x, int y)\n    {\n        if (x &lt; 0 || y &lt; 0 || x >= Width || y >= Height)\n            throw new Exception(\"Coordinates out of range\");\n        int a, r, g, b;\n        var p = PixelPointer(x, y);\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)\n        {\n            b = *p++;\n            g = *p++;\n            r = *p++;\n            a = *p;\n            return Color.FromArgb(a, r, g, b);\n        }\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)\n        {\n            b = *p++;\n            g = *p++;\n            r = *p;\n            return Color.FromArgb(r, g, b);\n        }\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)\n        {\n            a = *p;\n            return Color.FromArgb(a, a, a);\n        }\n        return default;\n    }\n    public void SetPixel(int x, int y, Color col)\n    {\n        if (x &lt; 0 || y &lt; 0 || x >= Width || y >= Height)\n            throw new Exception(\"Coordinates out of range\");\n        var p = PixelPointer(x, y);\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)\n        {\n            *p++ = col.B;\n            *p++ = col.G;\n            *p++ = col.R;\n            *p   = col.A;\n            return;\n        }\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)\n        {\n            *p++ = col.B;\n            *p++ = col.G;\n            *p   = col.R;\n            return;\n        }\n        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)\n            *p = col.B;\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Direct Access Pixel Data, GetPixel, SetPixel<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/48"}],"collection":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/comments?post=48"}],"version-history":[{"count":1,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/48\/revisions"}],"predecessor-version":[{"id":49,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/posts\/48\/revisions\/49"}],"wp:attachment":[{"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/media?parent=48"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/categories?post=48"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/michaeljohnsteiner.com\/index.php\/wp-json\/wp\/v2\/tags?post=48"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}