-
Notifications
You must be signed in to change notification settings - Fork 5k
/
FastBitmap.cs
90 lines (72 loc) · 2.63 KB
/
FastBitmap.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
//
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace Microsoft.Drawing
{
public struct PixelData
{
public byte B;
public byte G;
public byte R;
}
public unsafe class FastBitmap : IDisposable
{
private readonly Bitmap _bitmap;
private int _width;
private BitmapData _bitmapData = null;
private byte* _pBase = null;
private PixelData* _pInitPixel = null;
private Point _size;
private bool _locked = false;
public FastBitmap(Bitmap bmp)
{
_bitmap = bmp ?? throw new ArgumentNullException(nameof(bmp));
_size = new Point(bmp.Width, bmp.Height);
LockBitmap();
}
public PixelData* GetInitialPixelForRow(int rowNumber) => (PixelData*)(_pBase + rowNumber * _width);
public PixelData* this[int x, int y] => (PixelData*)(_pBase + y * _width + x * sizeof(PixelData));
public Color GetColor(int x, int y)
{
PixelData* data = this[x, y];
return Color.FromArgb(data->R, data->G, data->B);
}
public void SetColor(int x, int y, Color c)
{
PixelData* data = this[x, y];
data->R = c.R;
data->G = c.G;
data->B = c.B;
}
private void LockBitmap()
{
if (_locked) throw new InvalidOperationException("Already locked");
var bounds = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);
// Figure out the number of bytes in a row. This is rounded up to be a multiple
// of 4 bytes, since a scan line in an image must always be a multiple of 4 bytes
// in length.
_width = bounds.Width * sizeof(PixelData);
if (_width % 4 != 0) _width = 4 * (_width / 4 + 1);
_bitmapData = _bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
_pBase = (byte*)_bitmapData.Scan0.ToPointer();
_locked = true;
}
private void InitCurrentPixel() => _pInitPixel = (PixelData*)_pBase;
private void UnlockBitmap()
{
if (!_locked) throw new InvalidOperationException("Not currently locked");
_bitmap.UnlockBits(_bitmapData);
_bitmapData = null;
_pBase = null;
_locked = false;
}
public void Dispose()
{
if (_locked) UnlockBitmap();
}
}
}