VisualBasic.NET和GDI+共創圖標編輯器
如果想自己設計一個個性獨特的ico圖片,然后讓它成為如"我的電腦","回收站"這樣的圖標該怎么做?就只有用一些專門的畫圖工具。因為windows的的畫圖程序無法創建ico文件。于是本人利用.net和GDI+就編寫了一個這樣的畫圖工具。雖然現在有很多文章都介紹了GDI+技術,但都只是純粹的GDI+的簡單應用的介紹,至少我還沒有看見一篇利用GDI+開發一個完整軟件或程序片段的文章。
這個程序實現了以下的功能:將BMP、JPG、jpeg、GIF、.png、.tiff文件轉化成ico文件,可以對轉化后的文件進行編輯;創建并編輯一個新的ico文件;對已有的ico文件進行編輯。所有被編輯的文件都保存為ico文件,可以在任何可使用ico文件的地方使用它們。
我先說明一下什么是GDI+。GDI+ 是GDI(Windows 早期版本提供的圖形設備接口)的后續版本,是Microsoft Windows XP操作系統即后續版本的圖形顯示技術。它已經集成到了.net開發環境中,所以不管你的OS是什么版本,只要安裝了.NET框架,就有了GDI+(注意:是.net框架,而不是.net開發環境,所以win98中也可以使用GDI+)。當然它也提供了傳統的api,可以由.net或非.net開發工具調用它。由于他和GDI的使用有很大的差別,所以要使用GDI+就必須從頭學。GDI+要比GDI簡單得多。
現在就來看一下如何實現這個軟件:先添加picturebox,0penfiledialog,savefiledialog,colordialog,domainupdown,label控件;然后添加兩個菜單即它們的子菜單,添加的菜單如下"文件"菜單包括"新建","打開","保存","退出","功能"菜單包括"直線","選擇顏色"代碼如下,在代碼后給出程序說明:
| Public Class Form1 Inherits System.Windows.Forms.Form Public imagepen, newbit, changiamge, mpen 'movepen,moveb,,grh,filenames,endpen Dim xd, yd, xu, yu, pk, ps Private Sub MenuItem9_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles MenuItem9.Click '新建一個ico文件,即"新建"菜單 PictureBox1.Image = Nothing Dim bitnew As New System.Drawing.Bitmap(32, 32, Drawing.Imaging.PixelFormat.Format32bppArgb)'建立一個Bitmap對象,以便在它上面畫圖 Dim x, y For x = 0 To 31 For y = 0 To 31 bitnew.SetPixel(x, y, Color.Transparent)'將Bitmap的背景設置為透明 Next Next newbit = bitnew MenuItem3.Enabled = False'"選擇顏色"菜單不可用 MenuItem2.Enabled = True'"直線"菜單可用 End Sub Private Sub MenuItem6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)' Handles MenuItem6.Click '打開圖片文件即"打開"菜單" OpenFileDialog1.Filter = "ico文件(*.ico)|*.ico|圖像文件 (*.BMP;*.JPG;*.jpeg;*.GIF;*.png;*.tiff)|*.BMP;*.JPG;*.jpeg;*.GIF;*.png;*.tiff" OpenFileDialog1.FilterIndex = 2 OpenFileDialog1.ShowDialog() OpenFileDialog1.FileName = "" End Sub Private Sub MenuItem8_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles MenuItem8.Click Me.Close()'退出 End Sub Private Sub MenuItem7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles MenuItem7.Click '保存文件,即"保存"對話筐 PictureBox1.Cursor = System.Windows.Forms.Cursors.Default SaveFileDialog1.Filter = "ico文件(*.ico)|*.ico"'設置要保存的文件后綴 SaveFileDialog1.ShowDialog() If SaveFileDialog1.FileName <> "" Then If Not SaveFileDialog1.ShowDialog.Cancel Then Dim bmp As New System.Drawing.Bitmap(PictureBox1.Image, 32,32)'從PictureBox1.Image初始化Bitmap,設置保存為圖片的大小,標準ico圖由 32*32和16*16兩種格式組成,此處為32*32,你也可以設置為16*16 Dim ico As System.Drawing.Icon = ico.FromHandle(bmp.GetHicon()) '用Bitmap的句柄,初始化icon,他是專門處理ico文件的類 Dim file As New System.IO.FileStream(SaveFileDialog1.FileName(), IO.FileMode.Create)'創建文件流 ico.Save(file)'保存為ico文件 file.Close()'關閉流 End If End If End Sub Public Sub MenuItem2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles MenuItem2.Click '是用直線在新建的ico中畫圖 PictureBox1.Cursor =System.Windows.Forms.Cursors.Cross '在PictureBox1中鼠標的樣式 ColorDialog1.ShowDialog() Dim pen As New Pen(ColorDialog1.Color, DomainUpDown1.Text())'創建畫筆 imagepen = pen End Sub Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) 'Handles PictureBox1.MouseDown '當按下鼠標左鍵時獲取直線的起點 If e.Button = MouseButtons.Left Then xd = e.X / 8 : yd = e.Y / 8 End If End Sub Private Sub PictureBox1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) 'Handles PictureBox1.MouseUp '畫出直線 If PictureBox1.Cursor Is System.Windows.Forms.Cursors.Cross And ps <> 1 Then xu = e.X : yu = e.Y Me.k(1, imagepen, yu / 8, xu / 8, xd, yd) Else If OpenFileDialog1.FilterIndex = 1 Then xu = e.X : yu = e.Y Me.k(2, mpen, yu / 8, xu / 8, xd, yd) End If End If End Sub Public Sub k(ByVal k As Integer, ByVal drawtool As Object, ByVal x As Integer, ByVal y As Integer, ByVal xs As Integer, ByVal ys As Integer) If k = 1 Then PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage'自動容納圖片 PictureBox1.Image = newbit Dim Graphic As Graphics Graphic = Graphic.FromImage(Me.PictureBox1.Image)'在PictureBox1上畫圖 Graphic.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias'鋸齒削邊 Graphic.DrawLine(drawtool, y, x, xs, ys)'畫線 End If If k = 2 Then PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage PictureBox1.Image = changiamge Dim Graphic As Graphics Graphic = Graphic.FromImage(Me.PictureBox1.Image) Graphic.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias Graphic.DrawLine(drawtool, y, x, xs, ys) End If End Sub Private Sub MenuItem3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles MenuItem3.Click '對打開的ico文件用直線畫圖 ColorDialog1.ShowDialog() Dim m3pen As New Pen(ColorDialog1.Color, DomainUpDown1.Text())'建立畫筆 mpen = m3pen End Sub Private Sub OpenFileDialog1_FileOk(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) 'Handles OpenFileDialog1.FileOk '打開文件 If OpenFileDialog1.FilterIndex = 1 Then Dim m3pen As New Pen(Color.Black, DomainUpDown1.Text()) mpen = m3pen MenuItem2.Enabled = False MenuItem3.Enabled = True Else MenuItem3.Enabled = False MenuItem2.Enabled = False End If If OpenFileDialog1.FileName <> "" Then PictureBox1.Cursor = System.Windows.Forms.Cursors.Default Dim images As New System.Drawing.Bitmap(OpenFileDialog1.FileName) changiamge = images PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage PictureBox1.Image = images Me.Text = OpenFileDialog1.FileName End If End Sub Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) 'Handles MyBase.Load '由于剛運行次程序時,沒有打開的ico文件和新建立的ico對象所以不可以創建畫圖工具對象 MenuItem3.Enabled = False MenuItem2.Enabled = False End Sub End Class |
程序說明:
1. 如何新建ico文件:先初始化bitmap,然后在"功能"-》"直線"菜單代碼中創建畫筆,就可以開始畫了。此時只是創建的一個bitmap對象,是我們在picturebox中畫。畫完后將bitmap對象保存到文件,就完成了新建ico的文件。
2.如何打開已有的ico文件,并修改后保存它:判斷打開的文件是否是ico,如果不是就只顯示他,如果是就顯示并且初始化一個畫筆,通過"功能"-》"選擇顏色"來改變畫出直線的顏色和寬度,然后保存,就完成了對原來ico文件的修改。
3.保存文件和對非ico文件轉化為ico文件:通過打開文件,將非ico文件顯示在picturebox中,在用picturebox.image初始化bitmap對象,此句的實際作用是將當前的picturebox.image內容附給bitmap。用bitmap的句柄初始icon對象(處理ico文件的對象),作用是將非ico文件轉化為ico文件,建立文件流對象,在其中指定新文件名,和訪問方法(文件流是save方法的參數)使用icon對象的save保存,最后關閉文件流。
4.如何畫:當完成1或2后,就可以開始畫圖,畫圖是由sub k過程,mouse-down,mouse-up來實現的。此時調用mouse-down獲得直線的起點,在mouse-up中獲得直線終點,接著在mouse-up 中調用sub k過中程綁定bitmap對象到picturebox的image屬性,他的作用類似于有了一張可以畫畫的紙,并在sub k中用Graphic.FromImage(Me.PictureBox1.Image)語句創建Graphics對象,表示是在PictureBox1.Image的bitmap對象中畫,而不是在PictureBox1上畫,他們的區別在于前者是可以保存畫畫結果的,后者不可以。K的值表示是在新建的ico文件中畫還是修改以有的ico文件(k=2是表示修改已有的ico文件)
5.一些語句說明:dim pen …是指用鋼筆來畫,object.rawline(….)表示畫直線,
6.文件格式的轉換問題:你可以使用image對象的save的方法來轉換圖象的格式,但是我發現雖然他提供了icon格式,但轉化后不是ico文件,而是png文件。從網上的資料顯示這是.net的本身問題。順便提一下image對象無構造函數,他雖然標為必須繼承才可使用,但實際上不行,如要使用它要用他的fromfile或fromstream方法來構造它。
7.關于k的問題:當你看懂這篇文章后你一定會提出為什么在每條分支中的PictureBox1.SizeMode = PictureBoxSizeMode.StretchImage,PictureBox1.Image = changiamge這兩句代碼不可以與它后面的代碼分開放在其他地方,如k=1時放在"新建"菜單中的代碼部分,k=2是放在mouseup中的else后的if語句中!其實這兩句就是我在編寫這個程序時遇到的最大的難題,我用了兩個小時才的出這兩句代碼要放在了現在的位置。最后看資料并與朋友探討后得出3個結論:
1. .NET本身問題。
2.如果分開使PictureBox1.Image對象丟失(PictureBox1.Image返回的是bitmap對象),無法綁定到Graphics。
3. PictureBox1.Image對象在sub k中不可見。雖然我不知道那個結論是對的,但我將它寫了出來,僅供參考。
對于程序中的0penfiledialog,savefiledialog,colordialog,domainupdown,文件流的使用請見msdn。這5個只是為了輔助這個程序而使用的,如果要在這里講清楚那這片文章就太長了,而且這些的使用很簡單。我在程序中使用的畫圖工具是鋼筆,畫出的圖形是直線,這隊ico文件已經夠有了,如果你想使用其他工具,畫其他圖形,只要修改"功能"中的子菜單,和sub k代碼就夠了。
運行如圖:
更換后的"我的電腦"圖標