-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathBitmapUtils.cs
More file actions
153 lines (144 loc) · 5.41 KB
/
BitmapUtils.cs
File metadata and controls
153 lines (144 loc) · 5.41 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Media;
using Velctor.Utils;
namespace HeightNormalConverter;
static class BitmapUtils
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetHeightInt8(
IntPtr target,
int x,
int y,
int pixelWidth,
int pixelHeight,
int Bpp,
int channelOffset)//小于0代表是灰度
{
nint wrapx = Mod(x, pixelWidth);
nint wrapy = Mod(y, pixelHeight);
nint MemAddress = target + wrapy * Bpp * pixelWidth + wrapx * Bpp;
if (channelOffset >= 0)
return Marshal.ReadByte(MemAddress + channelOffset);
byte R = Marshal.ReadByte(MemAddress);
byte G = Marshal.ReadByte(++MemAddress);
byte B = Marshal.ReadByte(++MemAddress);
return (R * 19595 + G * 38469 + B * 7472) >> 16;
}
/// <param name="x">目标像素的x</param>
/// <param name="y">目标像素的y</param>
/// <param name="Address">目标点阵图的头指针</param>
/// <param name="pixelWidth">目标图片的像素宽度</param>
/// <param name="pixelHeight">目标图片的像素高度</param>
/// <param name="Bpp">每像素字节数</param>
/// <param name="channelOffset">目标通道在像素中的第几个字节位置,小于0代表要计算灰度</param>
/// <param name="unsigned">是无符号16位整数</param>
/// <param name="isBigEndinan">目标数据是大端存储的,false则为小端</param>
/// <returns>高程图的高度</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetHeightInt16(
IntPtr Address,
int x,
int y,
int pixelWidth,
int pixelHeight,
int Bpp,
int channelOffset,
bool unsigned,
bool isBigEndinan)
{
nint wrapx = Mod(x, pixelWidth);
nint wrapy = Mod(y, pixelHeight);
nint MemAddress = Address + (wrapy * Bpp * pixelWidth) + (wrapx * Bpp);
if (channelOffset < 0) {
ushort R = ReadInt16WithEndian(MemAddress + 0, isBigEndinan);
ushort G = ReadInt16WithEndian(MemAddress + 2, isBigEndinan);
ushort B = ReadInt16WithEndian(MemAddress + 4, isBigEndinan);
if (unsigned) return (R * 0.299f) + (G * 0.587f) + (B * 0.114f);
else {
return (Unsafe.As<ushort, short>(ref R) * 0.299f) +
(Unsafe.As<ushort, short>(ref G) * 0.587f) +
(Unsafe.As<ushort, short>(ref B) * 0.114f);
}
}
else {
ushort result = ReadInt16WithEndian(MemAddress + channelOffset, isBigEndinan);
return unsigned ? result : Unsafe.As<ushort, short>(ref result);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static unsafe ushort ReadInt16WithEndian(Ptr<ushort> Address, bool isBigEndinan)
{
return isBigEndinan ? BinaryPrimitives.ReadUInt16BigEndian(Address.CastAs<byte>().AsSpan()) : Address.Target;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetHeightFloat32(Ptr<float> pFloat, int x, int y, int pixelWidth, int pixelHeight, int Bpp, int channelOffset)
{
x = Mod(x, pixelWidth);
y = Mod(y, pixelHeight);
nint offset = ((nint)y * Bpp * pixelWidth) + ((nint)x * Bpp);
return channelOffset < 0
? (pFloat[offset] * 0.299f) + (pFloat[++offset] * 0.587f) + (pFloat[++offset] * 0.114f)
: pFloat[offset + (channelOffset / 4)];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Mod(int x, int y) => (x % y) + (x < 0 ? y : 0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte EncodeNormal(float component) => (byte)Math.Clamp(MathF.FusedMultiplyAdd(component, 127.5f, 127.5f), 0, 255);
public static PixelStruct GetPixelStructFromWPFFormat(PixelFormat format)
{
int BytesPerPixel = format.BitsPerPixel >> 3;
int ChannelCount = format.Masks.Count;
int BytesPerChannel = BytesPerPixel / ChannelCount;
int Roffset = 0;
int Goffset = 0;
int Boffset = 0;
int Aoffset = 0;
if (format == PixelFormats.Bgr32) { Roffset = 2; Goffset = 1; Boffset = 0; Aoffset = 0; }
else if (format == PixelFormats.Bgra32) { Roffset = 2; Goffset = 1; Boffset = 0; Aoffset = 4; }
else if (format == PixelFormats.Bgr24) { Roffset = 2; Goffset = 1; Boffset = 0; Aoffset = 0; }
else if (format == PixelFormats.Rgb24) { Roffset = 0; Goffset = 1; Boffset = 2; Aoffset = 0; }
else if (format == PixelFormats.Rgb48) { Roffset = 0; Goffset = 2; Boffset = 4; Aoffset = 0; }
else if (format == PixelFormats.Rgba128Float) { Roffset = 0; Goffset = 4; Boffset = 8; Aoffset = 12; }
else if (format == PixelFormats.Rgba64) { Roffset = 0; Goffset = 2; Boffset = 4; Aoffset = 6; }
else if (format == PixelFormats.Rgb128Float) { Roffset = 0; Goffset = 4; Boffset = 8; Aoffset = 0; }
return new() {
Roffset = Roffset,
Goffset = Goffset,
Boffset = Boffset,
Aoffset = Aoffset,
BytesPerPixel = BytesPerPixel,
ChannelCount = ChannelCount,
BytesPerChannel = BytesPerChannel,
};
}
public static bool IsTrue(this bool? value) => value.HasValue && value.Value;
}
struct PixelStruct
{
public int Roffset;
public int Goffset;
public int Boffset;
public int Aoffset;
public int BytesPerPixel;
public int BytesPerChannel;
public int ChannelCount;
public void WriteChannelOffset(int RGBA, int offset)
{
switch (RGBA) {
case 0: Roffset = offset; break;
case 1: Goffset = offset; break;
case 2: Boffset = offset; break;
case 3: Aoffset = offset; break;
}
}
public int GetChannelOffset(int RGBA) => RGBA switch {
0 => Roffset,
1 => Goffset,
2 => Boffset,
3 => Aoffset,
_ => throw new ArgumentException($"Channel {RGBA} is not exist."),
};
}