C# 画4位或8位图(将图片压缩成4位或8位)
画4位图同画8位图的思路有些类似。难点是C#里没有4位的数据类型。所以要想办法用已有的数据类型(比如byte)去操作4位的数据类型。
对于用C#画八位图的方法我上一篇文章有说过,这里就不再多说了(地址:http://www.cnblogs.com/wdh1983/archive/2009/01/20/1378468.html 文章内容虽没什么技术含量,但请转载时给个原址链接)。
废话就不说了,直接上代码
实际上,上面的压缩方法性能是比较低的,以前那个文章中有说过一个改进方法。但效果一般。
本文原创地址: http://www.cnblogs.com/wdh1983/archive/2009/10/15/1584048.html
如果你要压缩的图片是你自己用程序画的,比如你要画一个行情的折线图,或行情的K图,那么这里还有一个更好的压缩方法。
就是你在画图前肯定是知道自己会用到多少种颜色的,那么你先根据这些颜色建好调色板。另外,在你画图的时候,不要用原始的颜色之间话,比如红色,不要用Color.Red,用Color.FromArgb(X, X, X, index),其中X为任意(0,255),index为红色在你建好的那个调色板中的索引值。
压缩代码如下:
原创辛苦,转帖请注明出处。万分感谢!
对于用C#画八位图的方法我上一篇文章有说过,这里就不再多说了(地址:http://www.cnblogs.com/wdh1983/archive/2009/01/20/1378468.html 文章内容虽没什么技术含量,但请转载时给个原址链接)。
废话就不说了,直接上代码
1
using System;
2
using System.Collections.Generic;
3
using System.Drawing;//此次需要引入System.Drawing.dll
4
using System.Drawing.Imaging;
5
6
namespace ConsoleApplication_Draw
7
{
8
class Program
9
{
10
static void Main(string[] args)
11
{
12
Bitmap old_Image = new Bitmap(@"C:\Documents and Settings\weidonghai\桌面\test.bmp");
13
Bitmap new_Image = pictureZip(old_Image);
14
new_Image.Save(@"C:\Documents and Settings\weidonghai\桌面\test_1.bmp");
15
}
16
17
/// <summary>
18
/// 图片压缩,压缩后的位数由传入参数中的调色板颜色个数决定,如果颜色数大于256种,将返回原图
19
/// </summary>
20
/// <param name="image">将要压缩的元素图片</param>
21
/// <returns>经压缩函数处理后的图片</returns>
22
private static Bitmap pictureZip(Bitmap image_old)
23
{
24
int Width = image_old.Width;
25
int Height = image_old.Height;
26
27
// 1:首先分析原图颜色数,并创建颜色列表,以便后面创建调色板
28
List<Color> listColor = new List<Color>();
29
for (int y = 0; y < Height; y++)
30
{
31
for (int x = 0; x < Width; x++)
32
{
33
Color c = image_old.GetPixel(x, y);
34
if (!listColor.Contains(c))
35
{
36
listColor.Add(c);
37
}
38
}
39
}
40
41
// 2:当颜色数大于256时,就没法压缩了,所以返回原图
42
// 由于8位图最多只能包含256种颜色,当颜色数在( 16,256 ] 这个范围内,可压缩成8位图
43
// 4位图道理同上
44
Bitmap bitmap_new;
45
if (listColor.Count > 256)
46
return image_old;
47
else if (listColor.Count > 16)
48
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);
49
else
50
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format4bppIndexed);
51
52
// 3:根据颜色列表创建压缩图片的调色板
53
ColorPalette ImagePal = bitmap_new.Palette;
54
for (int i = 0; i < listColor.Count; i++)
55
{
56
ImagePal.Entries[i] = listColor[i];
57
}
58
bitmap_new.Palette = ImagePal;
59
60
// 4:因为原图可能不是32位的,这里要将原图变为32位的,以方便后面的压缩
61
Bitmap bitmap_oldCopy = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
62
{
63
Graphics g = Graphics.FromImage(bitmap_oldCopy);
64
g.PageUnit = GraphicsUnit.Pixel;
65
g.DrawImage(image_old, 0, 0, Width, Height);
66
g.Dispose();
67
}
68
69
// 5:将图片的数据锁定到系统内存中,用指针操作内存中的这些颜色数据快,实现压缩
70
Rectangle rect = new Rectangle(0, 0, Width, Height);
71
BitmapData bitmapData_new;
72
if (ImagePal.Entries.Length > 16)
73
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
74
else
75
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format4bppIndexed);
76
BitmapData bitmapData_old = bitmap_oldCopy.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
77
78
IntPtr pixels = bitmapData_new.Scan0;
79
unsafe
80
{
81
byte* pBits;
82
if (bitmapData_new.Stride > 0)
83
pBits = (byte*)pixels.ToPointer();
84
else
85
pBits = (byte*)pixels.ToPointer() + bitmapData_new.Stride * (Height - 1);
86
uint stride = (uint)Math.Abs(bitmapData_new.Stride);
87
88
byte* p = (byte*)bitmapData_old.Scan0;
89
int offset = bitmapData_old.Stride - Width * 4;
90
91
// 6:把内存中的数据看成是一个二维数组,遍历,一个点一个点的压缩
92
if (ImagePal.Entries.Length > 16)
93
{
94
for (uint row = 0; row < Height; ++row)
95
{
96
for (uint col = 0; col < Width; ++col)
97
{
98
Color pixel = Color.FromArgb(p[3], p[2], p[1], p[0]);
99
//获取新图对应点的指针
100
byte* p8bppPixel = pBits + row * stride + col;
101
//将原图这个点的颜色所对应的颜色索引值赋给指针
102
*p8bppPixel = (byte)listColor.IndexOf(pixel);
103
p += 4;
104
}
105
p += offset;
106
}
107
108
}
109
else
110
{
111
//四位图与八位图的不同之处是,要用一个byte同时操作两个四位数据
112
int _width = 0;
113
if (Width % 2 == 0) _width = Width / 2;
114
else _width = Width / 2 + 1;
115
for (uint row = 0; row < Height; row++)
116
{
117
for (uint col = 0; col < _width; col++)
118
{
119
Color pixel_1 = Color.FromArgb(p[3], p[2], p[1], p[0]);
120
Color pixel_2 = Color.FromArgb(p[7], p[6], p[5], p[4]);
121
byte index1 = (byte)listColor.IndexOf(pixel_1);
122
byte index2 = (byte)listColor.IndexOf(pixel_2);
123
124
byte* p8bppPixel = pBits + row * stride + col;
125
if (col != _width - 1)
126
{ //非每行最后一个元素
127
*p8bppPixel = (byte)(index1 * 16 + index2);
128
p += 8;
129
}
130
else
131
{ //每行最后一个元素
132
if (Width % 2 == 0)
133
{ //当图片宽度为偶数时
134
*p8bppPixel = (byte)(index1 * 16 + index2);
135
p += 8;
136
}
137
else
138
{ //当图片宽度为奇数时,这里是最特殊的地方
139
*p8bppPixel = (byte)(*p8bppPixel % 16 + index1 * 16);
140
p += 4;
141
}
142
}
143
}
144
p += offset;
145
}
146
}
147
bitmap_oldCopy.UnlockBits(bitmapData_old);
148
}
149
bitmap_oldCopy.Dispose();
150
bitmap_new.UnlockBits(bitmapData_new);
151
return bitmap_new;
152
}
153
}
154
}
using System;2
using System.Collections.Generic;3
using System.Drawing;//此次需要引入System.Drawing.dll4
using System.Drawing.Imaging;5

6
namespace ConsoleApplication_Draw7
{8
class Program9
{10
static void Main(string[] args)11
{12
Bitmap old_Image = new Bitmap(@"C:\Documents and Settings\weidonghai\桌面\test.bmp");13
Bitmap new_Image = pictureZip(old_Image);14
new_Image.Save(@"C:\Documents and Settings\weidonghai\桌面\test_1.bmp");15
}16

17
/// <summary>18
/// 图片压缩,压缩后的位数由传入参数中的调色板颜色个数决定,如果颜色数大于256种,将返回原图19
/// </summary>20
/// <param name="image">将要压缩的元素图片</param>21
/// <returns>经压缩函数处理后的图片</returns>22
private static Bitmap pictureZip(Bitmap image_old)23
{24
int Width = image_old.Width;25
int Height = image_old.Height;26

27
// 1:首先分析原图颜色数,并创建颜色列表,以便后面创建调色板28
List<Color> listColor = new List<Color>();29
for (int y = 0; y < Height; y++)30
{31
for (int x = 0; x < Width; x++)32
{33
Color c = image_old.GetPixel(x, y);34
if (!listColor.Contains(c))35
{36
listColor.Add(c);37
}38
}39
}40

41
// 2:当颜色数大于256时,就没法压缩了,所以返回原图42
// 由于8位图最多只能包含256种颜色,当颜色数在( 16,256 ] 这个范围内,可压缩成8位图43
// 4位图道理同上44
Bitmap bitmap_new;45
if (listColor.Count > 256)46
return image_old;47
else if (listColor.Count > 16)48
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);49
else50
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format4bppIndexed);51

52
// 3:根据颜色列表创建压缩图片的调色板53
ColorPalette ImagePal = bitmap_new.Palette;54
for (int i = 0; i < listColor.Count; i++)55
{56
ImagePal.Entries[i] = listColor[i];57
}58
bitmap_new.Palette = ImagePal;59

60
// 4:因为原图可能不是32位的,这里要将原图变为32位的,以方便后面的压缩61
Bitmap bitmap_oldCopy = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);62
{63
Graphics g = Graphics.FromImage(bitmap_oldCopy);64
g.PageUnit = GraphicsUnit.Pixel;65
g.DrawImage(image_old, 0, 0, Width, Height);66
g.Dispose();67
}68
69
// 5:将图片的数据锁定到系统内存中,用指针操作内存中的这些颜色数据快,实现压缩70
Rectangle rect = new Rectangle(0, 0, Width, Height);71
BitmapData bitmapData_new;72
if (ImagePal.Entries.Length > 16)73
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);74
else75
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format4bppIndexed);76
BitmapData bitmapData_old = bitmap_oldCopy.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);77

78
IntPtr pixels = bitmapData_new.Scan0;79
unsafe80
{81
byte* pBits;82
if (bitmapData_new.Stride > 0)83
pBits = (byte*)pixels.ToPointer();84
else85
pBits = (byte*)pixels.ToPointer() + bitmapData_new.Stride * (Height - 1);86
uint stride = (uint)Math.Abs(bitmapData_new.Stride);87

88
byte* p = (byte*)bitmapData_old.Scan0;89
int offset = bitmapData_old.Stride - Width * 4;90

91
// 6:把内存中的数据看成是一个二维数组,遍历,一个点一个点的压缩92
if (ImagePal.Entries.Length > 16)93
{94
for (uint row = 0; row < Height; ++row)95
{96
for (uint col = 0; col < Width; ++col)97
{98
Color pixel = Color.FromArgb(p[3], p[2], p[1], p[0]);99
//获取新图对应点的指针100
byte* p8bppPixel = pBits + row * stride + col;101
//将原图这个点的颜色所对应的颜色索引值赋给指针102
*p8bppPixel = (byte)listColor.IndexOf(pixel);103
p += 4;104
}105
p += offset;106
}107

108
}109
else110
{111
//四位图与八位图的不同之处是,要用一个byte同时操作两个四位数据112
int _width = 0;113
if (Width % 2 == 0) _width = Width / 2;114
else _width = Width / 2 + 1;115
for (uint row = 0; row < Height; row++)116
{117
for (uint col = 0; col < _width; col++)118
{119
Color pixel_1 = Color.FromArgb(p[3], p[2], p[1], p[0]);120
Color pixel_2 = Color.FromArgb(p[7], p[6], p[5], p[4]);121
byte index1 = (byte)listColor.IndexOf(pixel_1);122
byte index2 = (byte)listColor.IndexOf(pixel_2);123

124
byte* p8bppPixel = pBits + row * stride + col;125
if (col != _width - 1)126
{ //非每行最后一个元素127
*p8bppPixel = (byte)(index1 * 16 + index2);128
p += 8;129
}130
else131
{ //每行最后一个元素132
if (Width % 2 == 0)133
{ //当图片宽度为偶数时134
*p8bppPixel = (byte)(index1 * 16 + index2);135
p += 8;136
}137
else138
{ //当图片宽度为奇数时,这里是最特殊的地方139
*p8bppPixel = (byte)(*p8bppPixel % 16 + index1 * 16);140
p += 4;141
}142
}143
}144
p += offset;145
}146
}147
bitmap_oldCopy.UnlockBits(bitmapData_old);148
}149
bitmap_oldCopy.Dispose();150
bitmap_new.UnlockBits(bitmapData_new);151
return bitmap_new;152
}153
}154
}实际上,上面的压缩方法性能是比较低的,以前那个文章中有说过一个改进方法。但效果一般。
本文原创地址: http://www.cnblogs.com/wdh1983/archive/2009/10/15/1584048.html
如果你要压缩的图片是你自己用程序画的,比如你要画一个行情的折线图,或行情的K图,那么这里还有一个更好的压缩方法。
就是你在画图前肯定是知道自己会用到多少种颜色的,那么你先根据这些颜色建好调色板。另外,在你画图的时候,不要用原始的颜色之间话,比如红色,不要用Color.Red,用Color.FromArgb(X, X, X, index),其中X为任意(0,255),index为红色在你建好的那个调色板中的索引值。
压缩代码如下:
1
private static Bitmap pictureZipPlus(Bitmap image_old, ColorPalette ImagePal)
2
{
3
int Width = image_old.Width;
4
int Height = image_old.Height;
5
6
Bitmap bitmap_new;
7
if (ImagePal.Entries.Length > 16)
8
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);
9
else
10
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format4bppIndexed);
11
bitmap_new.Palette = ImagePal;
12
13
Bitmap bitmap_oldCopy = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
14
{
15
Graphics g = Graphics.FromImage(bitmap_oldCopy);
16
g.PageUnit = GraphicsUnit.Pixel;
17
g.DrawImage(image_old, 0, 0, Width, Height);
18
g.Dispose();
19
}
20
21
Rectangle rect = new Rectangle(0, 0, Width, Height);
22
BitmapData bitmapData_new;
23
if (ImagePal.Entries.Length > 16)
24
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
25
else
26
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format4bppIndexed);
27
IntPtr pixels = bitmapData_new.Scan0;
28
BitmapData bitmapData_old = bitmap_oldCopy.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
29
30
unsafe
31
{
32
byte* pBits;
33
if (bitmapData_new.Stride > 0)
34
pBits = (byte*)pixels.ToPointer();
35
else
36
pBits = (byte*)pixels.ToPointer() + bitmapData_new.Stride * (Height - 1);
37
uint stride = (uint)Math.Abs(bitmapData_new.Stride);
38
39
byte* p = (byte*)bitmapData_old.Scan0;
40
int offset = bitmapData_old.Stride - Width * 4;
41
42
if (ImagePal.Entries.Length > 16)
43
{
44
for (uint row = 0; row < Height; ++row)
45
{
46
for (uint col = 0; col < Width; ++col)
47
{
48
byte* p8bppPixel = pBits + row * stride + col;
49
*p8bppPixel = p[0];
50
p += 4;
51
}
52
p += offset;
53
}
54
55
}
56
else
57
{
58
int _width = 0;
59
if (Width % 2 == 0) _width = Width / 2;
60
else _width = Width / 2 + 1;
61
for (uint row = 0; row < Height; row++)
62
{
63
for (uint col = 0; col < _width; col++)
64
{
65
byte* p8bppPixel = pBits + row * stride + col;
66
if (col != _width - 1)
67
{
68
*p8bppPixel = (byte)(p[0] * 16 + p[4]);
69
p += 8;
70
}
71
else
72
{
73
if (Width % 2 == 0)
74
{
75
*p8bppPixel = (byte)(p[0] * 16 + p[4]);
76
p += 8;
77
}
78
else
79
{
80
*p8bppPixel = (byte)(*p8bppPixel % 16 + p[0] * 16);
81
p += 4;
82
}
83
}
84
}
85
p += offset;
86
}
87
}
88
bitmap_oldCopy.UnlockBits(bitmapData_old);
89
}
90
bitmap_oldCopy.Dispose();
91
bitmap_new.UnlockBits(bitmapData_new);
92
return bitmap_new;
93
}
private static Bitmap pictureZipPlus(Bitmap image_old, ColorPalette ImagePal)2
{3
int Width = image_old.Width;4
int Height = image_old.Height;5

6
Bitmap bitmap_new;7
if (ImagePal.Entries.Length > 16)8
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);9
else10
bitmap_new = new Bitmap(Width, Height, PixelFormat.Format4bppIndexed);11
bitmap_new.Palette = ImagePal;12

13
Bitmap bitmap_oldCopy = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);14
{15
Graphics g = Graphics.FromImage(bitmap_oldCopy);16
g.PageUnit = GraphicsUnit.Pixel;17
g.DrawImage(image_old, 0, 0, Width, Height);18
g.Dispose();19
}20

21
Rectangle rect = new Rectangle(0, 0, Width, Height);22
BitmapData bitmapData_new;23
if (ImagePal.Entries.Length > 16)24
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);25
else26
bitmapData_new = bitmap_new.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format4bppIndexed);27
IntPtr pixels = bitmapData_new.Scan0;28
BitmapData bitmapData_old = bitmap_oldCopy.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);29

30
unsafe31
{32
byte* pBits;33
if (bitmapData_new.Stride > 0)34
pBits = (byte*)pixels.ToPointer();35
else36
pBits = (byte*)pixels.ToPointer() + bitmapData_new.Stride * (Height - 1);37
uint stride = (uint)Math.Abs(bitmapData_new.Stride);38

39
byte* p = (byte*)bitmapData_old.Scan0;40
int offset = bitmapData_old.Stride - Width * 4;41

42
if (ImagePal.Entries.Length > 16)43
{44
for (uint row = 0; row < Height; ++row)45
{46
for (uint col = 0; col < Width; ++col)47
{48
byte* p8bppPixel = pBits + row * stride + col;49
*p8bppPixel = p[0];50
p += 4;51
}52
p += offset;53
}54

55
}56
else57
{58
int _width = 0;59
if (Width % 2 == 0) _width = Width / 2;60
else _width = Width / 2 + 1;61
for (uint row = 0; row < Height; row++)62
{63
for (uint col = 0; col < _width; col++)64
{65
byte* p8bppPixel = pBits + row * stride + col;66
if (col != _width - 1)67
{68
*p8bppPixel = (byte)(p[0] * 16 + p[4]);69
p += 8;70
}71
else72
{73
if (Width % 2 == 0)74
{75
*p8bppPixel = (byte)(p[0] * 16 + p[4]);76
p += 8;77
}78
else79
{80
*p8bppPixel = (byte)(*p8bppPixel % 16 + p[0] * 16);81
p += 4;82
}83
}84
}85
p += offset;86
}87
}88
bitmap_oldCopy.UnlockBits(bitmapData_old);89
}90
bitmap_oldCopy.Dispose();91
bitmap_new.UnlockBits(bitmapData_new);92
return bitmap_new;93
}原创辛苦,转帖请注明出处。万分感谢!


浙公网安备 33010602011771号