我最近在实现我的WMS服务器的时候,发现了一个超级郁闷的问题,问题描述如下:客户需要动态叠加一个透明层到底图上,比如说公交线路层,这个层有透明背景,于是可以叠加到其他图层上去。使用openlayer动态叠加图层很方便,我想这还不容易,使用透明png不就OK了,测试结果表明,在我机器的IE8上,非常正常。我正暗自得意,另一位兄弟用IE6一看,完蛋了,IE6不支持透明PNG,汗,这下要了命了,赶紧翻openlayers的资料,发现可以针对IE6特别使用透明滤镜。使用方法很方便,只要设置要透明的层 属性 alpha=true即可。测试后发现,透明是透明了,但是由于图片瓦块数过多,导致IE6被拖得半死,反应缓慢。汗,于是我想,那就对路线层使用gif格式呗,gif不也可以透明背景么。于是,悲剧出现了。为了解说清楚,我以一个PLMM为模特,嘿嘿
首先呢,我们准备一个PLMM,嘿嘿:![](https://images.cnblogs.com/cnblogs_com/ashei/PLMM.jpg)
大家看到PLMM帽子边上的那个黄色圆圈了吗?一会我们就要将它变成透明的,生成一张可以在IE6中透明的GIF图。
首先呢,我们使用常规方式:
1
Dim gif1 As New Bitmap("plmm.jpg")
2
gif1.MakeTransparent(Color.Yellow)
3
PictureBox1.Image = gif1
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'这里我将它保存为gif到流里,这里是内存流,在asp.net中则是outputstream ,再显示在picturebox2里
6
Dim ms As New System.IO.MemoryStream()
7
gif1.Save(ms, Imaging.ImageFormat.Gif)
8![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
9
Dim gif2 = Bitmap.FromStream(ms)
10
ms.Dispose()
11![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
12
PictureBox2.Image = gif2
13![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
14
'***变黑了****
这个结果是十分令人沮丧的:那个圆圈非但没透明,甚至还变成了黑色:
![](https://images.cnblogs.com/cnblogs_com/ashei/step1.JPG)
那么如果我直接保存为文件呢?图我就不贴了,和上面一样,还是黑的。
1
Dim gif1 As New Bitmap("plmm.jpg")
2
gif1.MakeTransparent(Color.Yellow)
3
PictureBox1.Image = gif1
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***直接保存为文件:***
6
gif1.Save("out1.gif", Imaging.ImageFormat.Gif)
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
'***还是黑的**********
9
PictureBox2.ImageLocation = "out1.gif"
这是我网上进行了一番搜索,大致上可以搜到这么一个版本:先修改调色板,然后再另外拷贝数据。
大致原理是:GIF是一种索引图像,最大色彩数256色 (PS:其实这个色彩数不少了,想当年,我上学时候经常逃课去玩
世嘉五代 MD游戏机,那个同屏发色数才16色,同期的超级任天堂的同屏发色数也不过256色,呵呵,这些都是从<<电子游戏软件>>里看来的)
GIF有一个调色板,最大有256个颜色索引,然后每个像素保存的是调色板的颜色索引值。故此,只需修改调色板,即可调整
图像的颜色。
OK,那么我们来改下调色板:
1
'***我们读取上一步生成的不透明gif
2
Dim gif As New Bitmap("out1.gif")
3
PictureBox1.Image = gif
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***获取色板***
6
Dim pal = gif.Palette
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
For i As Integer = 0 To pal.Entries.Length - 1
9
Dim color = pal.Entries(i)
10
'***将黑色改为透明,并且玩个反色特效,嘿嘿***
11
If color.R = 0 And color.G = 0 And color.B = 0 Then
12
pal.Entries(i) = color.Transparent
13
Else
14
pal.Entries(i) = color.FromArgb(255, color.B, color.G, color.R)
15
End If
16![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17
Next
18![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
19
Dim gif2 As Bitmap = gif.Clone()
20
gif2.Palette = pal
21![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22
PictureBox2.Image = gif2
结果如图:
看起来效果不错,纯黑色部分被透明了!而且么,还出来个反色特效,HOHO
不过你不要高兴得太早,如果这时候你保存的话,它还是黑的!!
这是我们需要使用拷贝位图数据的办法来处理:
1
'***我们读取上一步生成的不透明gif
2
Dim gif As New Bitmap("out1.gif")
3
PictureBox1.Image = gif
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***获取色板***
6
Dim pal = gif.Palette
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
For i As Integer = 0 To pal.Entries.Length - 1
9
Dim color = pal.Entries(i)
10
'***将黑色改为透明***
11
If color.R = 0 And color.G = 0 And color.B = 0 Then
12
pal.Entries(i) = color.Transparent
13
End If
14
Next
15![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
16
'***另外创建一个位图,格式为8位索引色**
17
Dim gif2 As New Bitmap(gif.Width, gif.Height, Imaging.PixelFormat.Format8bppIndexed)
18
'***设置修改后的调色板***
19
gif2.Palette = pal
20
'***拷贝内存
21![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22
Dim src = gif.LockBits(New Rectangle(0, 0, gif.Width, gif.Height), Imaging.ImageLockMode.ReadOnly, gif.PixelFormat)
23
Dim trg = gif2.LockBits(New Rectangle(0, 0, gif2.Width, gif2.Height), Imaging.ImageLockMode.WriteOnly, gif2.PixelFormat)
24![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
Dim bits(src.Stride * src.Height - 1) As Byte
26
System.Runtime.InteropServices.Marshal.Copy(src.Scan0, bits, 0, bits.Length)
27
System.Runtime.InteropServices.Marshal.Copy(bits, 0, trg.Scan0, bits.Length)
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
gif.UnlockBits(src)
30
gif2.UnlockBits(trg)
31![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
33
'***这时再保存,看看吧!***
34
gif2.Save("out3.gif")
35![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
36
Me.PictureBox2.ImageLocation = "out3.gif"
37![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
这时,我们保存了一个透明背景的gif图像!这个out3.gif,是背景透明的!
不过,如果你这时候认为大功告成的话,那可就错了,嘿嘿,这事情就是这么麻烦,请看:
1
'***我们读取上一步生成的不透明gif
2
Dim gif As New Bitmap("out1.gif")
3
PictureBox1.Image = gif
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***获取色板***
6
Dim pal = gif.Palette
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
For i As Integer = 0 To pal.Entries.Length - 1
9
Dim color = pal.Entries(i)
10
'***将黑色改为透明***
11
If color.R = 0 And color.G = 0 And color.B = 0 Then
12
pal.Entries(i) = color.Transparent
13
End If
14
Next
15![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
16
'***另外创建一个位图,格式为8位索引色**
17
Dim gif2 As New Bitmap(gif.Width, gif.Height, Imaging.PixelFormat.Format8bppIndexed)
18
'***设置修改后的调色板***
19
gif2.Palette = pal
20
'***拷贝内存
21![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22
Dim src = gif.LockBits(New Rectangle(0, 0, gif.Width, gif.Height), Imaging.ImageLockMode.ReadOnly, gif.PixelFormat)
23
Dim trg = gif2.LockBits(New Rectangle(0, 0, gif2.Width, gif2.Height), Imaging.ImageLockMode.WriteOnly, gif2.PixelFormat)
24![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
Dim bits(src.Stride * src.Height - 1) As Byte
26
System.Runtime.InteropServices.Marshal.Copy(src.Scan0, bits, 0, bits.Length)
27
System.Runtime.InteropServices.Marshal.Copy(bits, 0, trg.Scan0, bits.Length)
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
gif.UnlockBits(src)
30
gif2.UnlockBits(trg)
31![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
33
'***OK,这时候,我把它保存到流里***
34
Dim ms As New System.IO.MemoryStream()
35
gif2.Save(ms, Imaging.ImageFormat.Gif)
36![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
37
gif2.Dispose()
38![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
39
Dim gif3 As Bitmap = Bitmap.FromStream(ms)
40
ms.Dispose()
41![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
42
Me.PictureBox2.Image = gif3
43![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
44
'这时候你看到了,透明色又顽固地被去掉了,只是原来是黑色,现在成了白色
45![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
透明色又消失了,只是这次变成了白色-_____________________-
![](https://images.cnblogs.com/cnblogs_com/ashei/step3.JPG)
那么为啥保存为文件就可以,而保存到流却不行呢?
事情到了这一步,只好祭出Reflector了,看看M$到底是怎么保存的,实在不行我把保存为文件的代码拷贝一份出来再往流里写
按照Reflector的说法,M$在保存文件时,使用的是RawFormat:
1
public void Save(string filename)
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
3
this.Save(filename, this.RawFormat);
4
}
好吧,那我也传个 RawFormat进去
1
'***我们读取上一步生成的不透明gif
2
Dim gif As New Bitmap("out1.gif")
3
PictureBox1.Image = gif
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***获取色板***
6
Dim pal = gif.Palette
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
For i As Integer = 0 To pal.Entries.Length - 1
9
Dim color = pal.Entries(i)
10
'***将黑色改为透明***
11
If color.R = 0 And color.G = 0 And color.B = 0 Then
12
pal.Entries(i) = color.Transparent
13
End If
14
Next
15![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
16
'***另外创建一个位图,格式为8位索引色**
17
Dim gif2 As New Bitmap(gif.Width, gif.Height, Imaging.PixelFormat.Format8bppIndexed)
18
'***设置修改后的调色板***
19
gif2.Palette = pal
20
'***拷贝内存
21![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22
Dim src = gif.LockBits(New Rectangle(0, 0, gif.Width, gif.Height), Imaging.ImageLockMode.ReadOnly, gif.PixelFormat)
23
Dim trg = gif2.LockBits(New Rectangle(0, 0, gif2.Width, gif2.Height), Imaging.ImageLockMode.WriteOnly, gif2.PixelFormat)
24![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
Dim bits(src.Stride * src.Height - 1) As Byte
26
System.Runtime.InteropServices.Marshal.Copy(src.Scan0, bits, 0, bits.Length)
27
System.Runtime.InteropServices.Marshal.Copy(bits, 0, trg.Scan0, bits.Length)
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
gif.UnlockBits(src)
30
gif2.UnlockBits(trg)
31![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
33
'***按照reflector的说法,它使用的是RawFormat***
34
Dim ms As New System.IO.MemoryStream()
35
Try
36
gif2.Save(ms, gif2.RawFormat)
37
Catch ex As Exception
38
MsgBox(ex.ToString(), MsgBoxStyle.Critical)
39
Finally
40![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
41
gif2.Dispose()
42![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
43
End Try
44![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
45![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
结果如图:这真是太BT了,我受不了了!!!
![](https://images.cnblogs.com/cnblogs_com/ashei/error.JPG)
经过比较发现,M$的两个保存是不一样的,保存为文件时,多了一个判断!保存到文件时,M$会调用png编码器,而保存到流则不会
1
public void Save(string filename, ImageFormat format)
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
3
if (format == null)
4![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
throw new ArgumentNullException("format");
6
}
7
ImageCodecInfo encoder = format.FindEncoder();
8
if (encoder == null) //这里比保存到流多了个判断!
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10
encoder = ImageFormat.Png.FindEncoder();
11
}
12
this.Save(filename, encoder, null);
13
}
14![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
15
public void Save(Stream stream, ImageFormat format)
16![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
17
if (format == null)
18![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
19
throw new ArgumentNullException("format");
20
}
21
ImageCodecInfo encoder = format.FindEncoder();
22
//这里没有那个获取默认编码器的步骤!!!
23
24
this.Save(stream, encoder, null);
25
}
26![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
27
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
30![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
OK,既然是这样,那么我就在外面调用一下那个传说中的 ImageFormat.Png.FindEncoder();
不就得了吗?你要是这样想那就太天真了:
1
internal ImageCodecInfo FindEncoder()
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
3
foreach (ImageCodecInfo info in ImageCodecInfo.GetImageEncoders())
4![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
5
if (info.FormatID.Equals(this.guid))
6![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
7
return info;
8
}
9
}
10
return null;
11
}
看到了吧,FindEncoder()方法是internal的 -______-,瀑布汗啊瀑布汗
不过还好,天无绝人之路,Save还有一个重载:
public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
我们可以直接传Png的ImageCodecInfo进去,嘿嘿,我们可以把png的ImageCodeInfo给穷举找出来!
1![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
Private Shared Function GetEncoderInfo()Function GetEncoderInfo(ByVal mimeType As String) As Imaging.ImageCodecInfo
2
For Each ecoder In Imaging.ImageCodecInfo.GetImageEncoders()
3
If ecoder.MimeType = mimeType Then
4
Return ecoder
5
End If
6
Next
7
Return Nothing
8
End Function
至此,我们终于制作了一个可以在IE6中拥有透明背景色的"gif"图像,不过实际上,这个其实不是gif格式的,实际上
是8位色png格式的,不过不管怎么说,这个好歹可以在IE6里透明了,而且使用上没有区别。除了不能动画,汗。
最后的实现代码:
1
'***我们读取上一步生成的不透明gif
2
Dim gif As New Bitmap("out1.gif")
3
PictureBox1.Image = gif
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
'***获取色板***
6
Dim pal = gif.Palette
7![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
8
For i As Integer = 0 To pal.Entries.Length - 1
9
Dim color = pal.Entries(i)
10
'***将黑色改为透明***
11
If color.R = 0 And color.G = 0 And color.B = 0 Then
12
pal.Entries(i) = color.Transparent
13
End If
14
Next
15![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
16
'***另外创建一个位图,格式为8位索引色**
17
Dim gif2 As New Bitmap(gif.Width, gif.Height, Imaging.PixelFormat.Format8bppIndexed)
18
'***设置修改后的调色板***
19
gif2.Palette = pal
20
'***拷贝内存
21![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22
Dim src = gif.LockBits(New Rectangle(0, 0, gif.Width, gif.Height), Imaging.ImageLockMode.ReadOnly, gif.PixelFormat)
23
Dim trg = gif2.LockBits(New Rectangle(0, 0, gif2.Width, gif2.Height), Imaging.ImageLockMode.WriteOnly, gif2.PixelFormat)
24![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
Dim bits(src.Stride * src.Height - 1) As Byte
26
System.Runtime.InteropServices.Marshal.Copy(src.Scan0, bits, 0, bits.Length)
27
System.Runtime.InteropServices.Marshal.Copy(bits, 0, trg.Scan0, bits.Length)
28![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
29
gif.UnlockBits(src)
30
gif2.UnlockBits(trg)
31![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
33![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
34
Dim ms As New System.IO.MemoryStream()
35![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
36
gif2.Save(ms, GetEncoderInfo("image/png"), Nothing)
37
gif2.Dispose()
38![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
39
Dim gif3 = Bitmap.FromStream(ms)
40![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
41
Me.PictureBox2.Image = gif3
42![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
最终正确的结果:
![](https://images.cnblogs.com/cnblogs_com/ashei/step4.JPG)
代码下载
最后,这就是我开发的山寨WMS生成的透明gif图层+openlayers的效果,哈哈,上次是
谁说最低限度也要supmap,山寨一定是不可能完成的任务来着?这是啥咧,HOHO,纯VB.NET的WMS哦,呵呵
学GIS,还是要自己做东西提高的才快,用商业的东西,又贵,还没啥提高,不就是用人家的组件么.
![](https://images.cnblogs.com/cnblogs_com/ashei/wms.JPG)