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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
| using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net;
using System.Windows.Forms;
namespace WindowsFormsApplication297
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var img = (Bitmap)Image.FromStream(new WebClient().OpenRead("http://www.cs.cmu.edu/~chuck/lennapg/len_std.jpg"));
BackgroundImage = img;
BackgroundImageLayout = ImageLayout.Center;
new Button() { Parent = this, Text = "Process" }.Click += delegate { Process(img); Invalidate(); };
}
private void Process(Bitmap img)
{
using (var wr = new ImageWrapper(img, true))
for (int x = 0; x < wr.Width; x++ )
for (int y = 0; y < wr.Height; y += 2)
{
var br = (int)(wr[x, y].GetBrightness() * 255);
wr[x, y] = Color.FromArgb(br, br, br);
}
}
}
/// <summary>
/// Враппер над Bitmap для быстрого чтения и изменения пикселов.
/// Также, класс контролирует выход за пределы изображения. При чтении за границей изображения - возвращает DefaultColor, при записи за границей изображения - игнорирует присвоение.
/// </summary>
public class ImageWrapper : IDisposable, IEnumerable<Point>
{
public int Width { get; private set; }
public int Height { get; private set; }
public Color DefaultColor { get; set; }
private byte[] data;
private byte[] outData;
private int stride;
private BitmapData bmpData;
private Bitmap bmp;
public ImageWrapper(Bitmap bmp, bool copySourceToOutput = false)
{
Width = bmp.Width;
Height = bmp.Height;
this.bmp = bmp;
bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
stride = bmpData.Stride;
data = new byte[stride * Height];
System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, data, 0, data.Length);
outData = copySourceToOutput ? (byte[])data.Clone() : new byte[stride * Height];
}
public Color this[int x, int y]
{
get
{
var i = GetIndex(x, y);
return i < 0 ? DefaultColor : Color.FromArgb(data[i + 3], data[i + 2], data[i + 1], data[i]);
}
set
{
var i = GetIndex(x, y);
if (i >= 0)
{
outData[i] = value.B;
outData[i + 1] = value.G;
outData[i + 2] = value.R;
outData[i + 3] = value.A;
};
}
}
public Color this[Point p]
{
get { return this[p.X, p.Y]; }
set { this[p.X, p.Y] = value; }
}
public void SetPixel(Point p, double r, double g, double b)
{
if (r < 0) r = 0;
if (r >= 256) r = 255;
if (g < 0) g = 0;
if (g >= 256) g = 255;
if (b < 0) b = 0;
if (b >= 256) b = 255;
this[p.X, p.Y] = Color.FromArgb((int) r, (int) g, (int) b);
}
int GetIndex(int x, int y)
{
return (x < 0 || x >= Width || y < 0 || y >= Height) ? -1 : x * 4 + y * stride;
}
public void Dispose()
{
System.Runtime.InteropServices.Marshal.Copy(outData, 0, bmpData.Scan0, outData.Length);
bmp.UnlockBits(bmpData);
}
public IEnumerator<Point> GetEnumerator()
{
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
yield return new Point(x, y);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
} |