منتدى فيجوال بيسك لكل العرب | منتدى المبرمجين العرب

نسخة كاملة : التعامل مع الصور Images في بيئة الدوت نت باستخدام +GDI - الجزء الأول
أنت حالياً تتصفح نسخة خفيفة من المنتدى . مشاهدة نسخة كاملة مع جميع الأشكال الجمالية .
كاتب الموضوع : silverlight

التعامل مع الصور Images في بيئة الدوت نت باستخدام +GDI
اللغة المستخدمة: الفيجوال بيسك
التطبيق: فيجوال استوديو 2005 و 2008
المستوي: التقييم متروك للقارئ
إعداد: مهندس / عمر أمين إبراهيم

هناك أكثر من أسلوب أو أكثر من طريقة لكي نضيف صورا الي الفورم ومن ثم نعرض هذه الصور داخل الفورم و بعض هذه الطرق يمكن تصنيفها كالتالي:-
الطريقة الأولي: استخدام اسم ملف لصورة ما.
الطريقة الثانية: استخدام Resources الخاصة بالمشروع
الطريقة الثالثة: استخدام ImageList Control
الطريقة الرابعة: استخدام ToBase64String مع MemoryStream
الطريقة الخامسة: استخدام OpenFileDialog
الطريقة السادسة: تعريف الصورة عن طريق Size معين وأيضا من الممكن استخدام PixelFormat ورسمها من الصفر ولقد أعطينا مثالا علي ذلك في المقدمة الخاصة بالمقال
وللمزيد من التفاصيل يمكنكم دراسة Bitmap Class ومعرفة كيفية إنشاء الصورة. أي عليكم دراسة Constructor الخاص بهذا الكلاس
الأن لنوضح كيفية استخدام بعض الطرق أعلاه
الطريقة الأولي:
هذه الطريقة تعتمد علي استخدام اسم الملف ومكانه علي الهارد ديسك
لو أننا بالفعل نعلم مكان الصورة واسم الملف الخاص بالصورة الموجودة علي الهارد ديسك فكل ما علينا عمله هو أن نقوم بتعريف هذه الصورة ومن ثم نقوم بعرضها داخل PictureBox أو من الممكن أن نقوم برسم الصورة بأي مكان داخل الفورم وهذه الطريقة ليست فعالة تماما
والسبب في عدم فعالية هذه الطريقة أننا عندما نقوم بتصميم برنامج ما فإننا لا نصممه لأنفسنا فقط وبما أن الصورة التي نستخدمها موجودة فقط داخل جهاز الكمبيوتر لدينا فإنه سوف يحدث خطأ عند تحميل الصورة وذلك عندما يقوم شخص أخر باستخدام البرنامج علي جهاز الكمبيوتر الخاص به ولكننا سوف نري كيف نستفيد من هذا الأسلوب بفعالية أكثر لاحقا
مثال علي الطريقة الأولي
افتح مشروع جديد ثم عليك إضافة PictureBox إليه ثم اكتب الكود التالي


كود :
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim bmp As Bitmap = New Bitmap("C:\img.gif")
PictureBox1.Image = bmp
End Sub

End Class
نلاحظ في المثال أعلاه أننا حددنا مكان الصورة علي الهارد ديسك وأن الصورة قد تم تعريفها في الحدث Load الخاص بالفورم ولو أخذت نفس المثال وحاولت تجربته علي جهازك فإنه سيحدث خطأ عند التشغيل والسبب ببساطه أن الصورة المستخدمة غير موجودة علي جهاز الكمبيوتر الخاص بك بل هي موجودة علي جهاز الكمبيوتر الخاص بي فقط لذا لكي يعمل المثال جيدا عليك أن تستخدم صورة موجودة علي جهازك أنت ويجب عليك مراعاة كتابة اسم الملف ومكانه بدون أي خطأ

مثال أخر علي الطريقة الأولي
افتح مشروع جديد ثم عليك إضافة PictureBox و أيضا أضف له باتون ثم اكتب الكود التالي


كود :
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim bmp As Bitmap = New Bitmap("C:\img.gif")
PictureBox1.Image = bmp

End Sub

End Class
الهدف هنا من إضافة الباتون هو أن نتجنب حدوث خطأ عند تشغيل البرنامج مباشرة ولكن نفس المشكلة مازالت موجودة حيث أن الملف المستخدم لا يوجد علي جهاز الكمبيوتر الخاص بك وبالتالي عليك استخدام ملف موجود بالفعل علي جهازك
إذن كيف نبتعد قليلا عن هذه المشكلة وأقصد هنا مشكلة عدم وجود الملف علي جهازك. ممكن مثلا أن نضع شرطا بحيث انه لو لم تكن الصورة موجودة علي جهاز المستخدم فإنه لا يتم تنفيذ الكود وتظهر رسالة توضح للمستخدم أن الصورة ليست موجودة علي جهازه والكود التالي يوضح ذلك


كود :
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Try
Dim bmp As Bitmap = New Bitmap("C:\img.gif")
PictureBox1.Image = bmp
Catch ex As Exception
MessageBox.Show("الصورة المستخدمة غير موجودة علي جهاز الكمبيوتر لديك من فضلك استخدم صورة اخري", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)

End Try

End Sub

End Class
سنلاحظ هنا عند تنفذ الكود علي جهازك أن لن يحدث خطأ بالبرنامج عند الضغط علي الباتون لأنه عند تجربة الكود ستظهر رسالة الخطأ فقط للمستخدم ولكن ما زال هذا الأسلوب في استخدام الصور داخل الفورم غير فعال تماما

الطريقة الثانية:
تعتمد هذه الطريقة علي إضافة الصور الي Resources الخاصة بالمشروع
وهذه الطريقة أفضل قليلا من الطريقة الأولي وهي ببساطة أننا نضيف الصور الي Resources الخاصة بالمشروع وبالتالي ستكون الصور موجودة مع البرنامج ومن ثم يمكن أن نستخدمها في أي وقت داخل البرنامج الخاص بنا بدون أن يحدث خطأ ولكن علينا أن نضع في حساباتنا شيئا هاما وهو انه كلما أضفنا صورا كثيرة الي Resources المشروع فإن الحجم النهائي للمشروع يكون كبيرا جدا لذلك فإن أهم نقاط القصور في استخدام هذا الأسلوب هو أن حجم البرنامج سيكون كبيرا كلما أضفنا صورا أكثر للمشروع
ولنتعلم أولا كيف نضيف صورة الي Resources المشروع والطريقة قد تكون صعبة قليلا لمن لم ينفذا سابقا ولكنها في النهاية أسلوب تكراراي فلو فعلتها مرة تستطيع أن تفعلها ملايين المرات بعد ذلك
يتم إضافة صورة الي Resources المشروع عن طريق إتباع الخطوات التالية
الذهاب الي نافذة Solution Explorer حيث سنجد في اعلي النافذة أربعة أيقونات وهنا نقوم بالضغط علي الأيقونة الثانية من جهة اليسار
عند الضغط علي هذه الأيقونة بالماوس سيظهر لنا جميع الملفات الموجودة تحت فهرس المشروع الخاص بنا ونختار منها MyProject
ثم نختار Resources وهنا سنجد أن هناك أيقونات أخري قد ظهرت في نافذة Solution Explorer وعلينا أن نختار منها الأيقونة الأولي من جهة اليمين ويمكن تنفذ هذه الخطوة بأن نقف بالماوس علي كلمة Resources ونضغط يمين الماوس وهنا ستظهر لنا ContextMenu نختار منها View Designer وهنا ستفتح لنا نافذة أخري ومنها سنجد مجموعه من الباتون في أعلاها ونختار منها Add Resource وهو باتون به سهم صغير و رأس هذا السهم متجهه لأسفل ولو ضغطنا بالماوس علي هذا السهم الصغير ستظهر لنا Drop Down Menu نختار منها Add Existing File ثم نختار الملف أو الملفات التي نريد إضافتها للمشروع وطبعا سوف نضيف علي الأقل هنا ملف لأي صورة موجودة علي جهازنا
بعد إضافة الصورة سنجد أن الفيجوال استوديو قد قام بإنشاء فهرس اسمه Resources حيث يمكننا الأن رؤية هذا الفهرس من داخل نافذة Solution Explorer
من الأشياء الهامة التي يجب أخذها في الاعتبار عند حذف صورة ما من Resources هو أن نفعل ذلك من داخل نافذة Resources نفسها أولا قبل أن نحذف الصورة من داخل فهرس Resources الذي تم إضافته للمشروع
الأن وقد أصبح لدينا صورة ما موجودة بالفعل داخل Resources المشروع الخاص بنا فإن كل ما علينا أن نفعله أن نستخدمها والمثال التالي يوضح ذلك
مثال علي الطريقة الثانية
افتح مشروع جديد ثم عليك إضافة PictureBox و أيضا أضف له باتون ثم اكتب الكود التالي


كود :
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim bmp As Bitmap = New Bitmap(My.Resources.img)
PictureBox1.Image = bmp

End Sub

End Class
وهذا شكل أخر لنفس المثال حيث هنا سنقوم بتحميل الصورة مباشرة في الحدث Load الخاص بالفورم


كود :
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim bmp As Bitmap = New Bitmap(My.Resources.img)
PictureBox1.Image = bmp
End Sub

End Class
وهذا شكل أخر للمثال ولكننا هنا سوف نقوم برسم الصورة داخل الفورم بأبعاد جديدة من داخل الحدث Paint الخاص بالفورم


كود :
Public Class Form1

Dim bmp As Bitmap = New Bitmap(My.Resources.img)

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.DrawImage(bmp, New Rectangle(0, 0, 100, 100))

End Sub

End Class
وهذا شكل أخر للمثال حيث سنقوم برسم الصورة لتغطي الفورم كاملا ولكن في هذه الحالة علينا أن نراعي أنه عند تكبير الفورم أو تغيير حجمه فإننا يجب أن نعيد رسم الصورة مرة أخري داخل الفورم لذلك في الحدث Resize الخاص بالفورم علينا أن نستخدم Invalidate لكي نجبر الفورم علي إعادة رسم الصورة عندما تتغير أبعاد الفورم لسبب ما مثل أن يقوم المستخدم بتكبير الفورم مثلا وسنلاحظ هنا أنه عند محاولة تكبير الفورم باستخدام الماوس سيحدث Flickering للفورم أي أننا سنشعر أن الفورم يهتز قليلا ولتجنب حدوث ذلك علينا أن نقوم بتغيير قيمة خاصية DoubleBuffered الي True يمكن أن تفعل ذلك في مرحلة Design أو أن تكتب الكود الخاص بذلك في الحدث Load الخاص بالفورم


كود :
Public Class Form1

Dim bmp As Bitmap = New Bitmap(My.Resources.img)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

DoubleBuffered = True

End Sub

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

e.Graphics.DrawImage(bmp, Me.ClientRectangle)

End Sub

Private Sub Form1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Resize
Invalidate()
End Sub

End Class
ملحوظه هامة : لكي نتجنب تماما حدوث خطأ عند تحميل الصورة لذا علينا أن نقوم بتعديل خاصية Build Action لهذه الصورة بأن نجعل قيمتها تساوي Embedded Resource وبالتالي تكون موجودة داخل الملف التنفيذي نفسه عند عمل Compile للمشروع ويتم ذلك بإتباع الخطوات التالية
نذهب الي الفهرس Resources الموجود في نافذة Solution Explorer ثم نختار الصورة ثم من نافذة Properties نقوم بتغيير نوع Build Action لهذه الصورة الي Embedded Resource
الطريقة الثالثة:
تعتمد هذه الطريقة علي أن نضيف صور الي المشروع عن طريق استخدام ImageList Control
ثم نضيف صورة أو مجموعه من الصور الي ImageList Control عن طري الصفة Images و لكن علينا أن نراعي شيئا هاما عند استخدام هذا الكونترول وهو أن أقصي أبعاد للصورة التي من الممكن أن نضيفها لهذا الكونترول يجب أن لا تتعددي 256*256 وهذان البعدان يمثلان طول وعرض الصورة وأيضا عند استخدام صور أبعادها تساوي 256*256 سنجد أن الصورة لا تظهر بشكلها الطبيعي عند عرضها في الفورم داخل PictureBox مثلا أو حتى عند محاولة رسمها داخل الفورم وهذا أحد أوجه القصور في هذا الكونترول.
طبعا كلنا نعلم انه بعد إضافة الصور فإن كل صورة داخل هذا الكونترول سيكون لها رقم أو Index حيث من الممكن أن نستدعي أي صورة موجودة داخل هذا الكونترول باستخدام Index الخاص بها
ملحوظة: يفضل استخدام هذه الطريقة مع الصور التي أبعادها صغيرة مثل الأيقونات علي سبيل المثال

مثال علي الطريقة الثالثة

افتح مشروع ثم عليك أن تضيف الي الفورم ImageList Control ثم أضف الي هذه الكونترول مجموعة من الصور المختلفة ثم يمكنك أن تستخدم الكود بالشكل التالي لعرض الصور داخل PictureBox أو من الممكن رسم الصورة داخل الفورم نفسه


كود :
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim bmp As Bitmap = ImageList1.Images(0)
PictureBox1.Image = bmp
PictureBox1.SizeMode = PictureBoxSizeMode.CenterImage

End Sub

End Class
وسنلاحظ في المثال السابق أن الرقم صفر يعبر عن Index الخاص بالصورة الأولي الموجودة داخل ImageList Control
شكل أخر للمثال هو أن نرسم الصورة داخل الفورم


كود :
Public Class Form1

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim bmp As Bitmap = ImageList1.Images(0)
e.Graphics.DrawImage(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height))

End Sub

End Class
سنلاحظ بالمثال السابق أن الصورة ستظهر مشوهة بالرغم أنني قد حاولت رسمها بنفس أبعادها
مثال علي الطريقة الرابعة
افتح مشروع جديد وأضف له PictureBox ثم استخدم الكود التالي


كود :
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim s As String = "Qk16AQAAAAAAADYAAAAoAAAAIwAAAAMAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5ANj+RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5ANj+RzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMANj+"

Dim ImageStream As IO.Stream = New System.IO.MemoryStream(Convert.FromBase64String(s))

Dim bmp As Bitmap = New Bitmap(ImageStream)

PictureBox1.Image = bmp
PictureBox1.SizeMode = PictureBoxSizeMode.CenterImage

End Sub

End Class
مثال أخر علي الطريقة الرابعة
افتح مشروع ثم استخدم الكود التالي لرسم الصورة من داخل الحدث Paint الخاص بالفورم


كود :
Public Class Form1

Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

Dim s As String = "Qk16AQAAAAAAADYAAAAoAAAAIwAAAAMAAAABABgAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5uGMyuGMy+/n5+/n5ANj+RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5wm8/RzIomHRh+/n5ANj+RzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMzHtMRzIoRzIozHtMANj+"

Dim ImageStream As IO.Stream = New System.IO.MemoryStream(Convert.FromBase64String(s))

Dim bmp As Bitmap = New Bitmap(ImageStream)

e.Graphics.DrawImage(bmp, New Rectangle(0, 0, 100, 100))

End Sub

End Class
الطريقة الخامسة:
تعتمد هذه الطريقة علي استخدام OpenFileDialog ومن ثم تحميل الصورة أو رسمها أو استخدامها كما نريد
مثال علي الطريقة الخامسة
افتح مشروع جديد وأضف الي الفورم OpenFileDialog وباتون و PictureBox ثم استخدم الكود التالي


كود :
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

With OpenFileDialog1

.Multiselect = False
.Filter = "All Files|*.*|Bitmaps|*.bmp|GIFs|*.gif|JPEGs|*.jpg|PNGs|*.png"
.FilterIndex = 1
.FileName = ""

End With

If OpenFileDialog1.ShowDialog() = DialogResult.OK Then

With PictureBox1
.Image = Image.FromFile(OpenFileDialog1.FileName)
.SizeMode = PictureBoxSizeMode.CenterImage
End With

End If

End Sub

End Class
في واقع الأمر هناك أفكار أخري من الممكن استخدامها لإضافة صور الي المشروع ومنها غلي سبيل المثال استخدام الداتا بيز مثل استخدام SQL أو استخدام MS Access لتخزين البيانات داخل ملف ثم استرجاع هذه البيانات في أي وقت نريده أو نتعامل معها كيفما شئنا
وهذه الطريقة سيكون لها مقال خاص بها لأهميتها
الأن وبعد أن ناقشنا كيفية إضافة الصور في بيئة الدوت نت لنسأل أنفسنا كيف نستفيد من مجموعة الأكواد السابقة بحيث يكون لدينا بالنهاية داله أو Function معينة يمكننا استخدامها في أي وقت نشاء وكما تحدثت سابقا فإن الهدف من هذا المقال هو إنشاء كلاس عام يمكننا أن نحوله الي ملف DLL وبالتالي يمكن أن نستخدمه في أي وقت نشاء بدون الحاجة الي تكرار كتابة الكود أكثر من مرة داخل الفورم
هيا بنا نبني أول Function من مجموعة الأكواد السابقة الخاصة بالجزء الأول في موضوعنا هذا وهو كيفية إضافة الصور الي الفورم
الكود التالي يوضح شكل Function ولقد أطلقت عليها اسم LoadImageFile


كود :
Public Shared Function LoadImageFile()

Dim ofd As New OpenFileDialog
With ofd
.Multiselect = False
.Filter = "All Files|*.*|Bitmaps|*.bmp|GIFs|*.gif|JPEGs|*.jpg|PNGs|*.png"
.FilterIndex = 4
.FileName = "Select image file"
End With

Dim bmpFile As String = ofd.FileName

If ofd.ShowDialog() <> DialogResult.OK Then
bmpFile = Nothing
Else
bmpFile = ofd.FileName

End If

LoadImageFile = bmpFile

End Function ' LoadImageFile Function
حاول عزيزي القارئ أن تقارن بين هذه Function والكود الموجود في المثال رقم الأول الخاص بالطريقة الأولي لإضافة الصور الي الفورم وأيضا الكود الموجود في المثال الأخير الخاص بالطريقة الخامسة ستجد أنه قد تم استخدامهما معا لإنشاء Function وسنلاحظ أيضا أن هذه Function تسترجع قيمة أو تساوي قيمة وهي عبارة عن String وهذا String قيمته تساوي File Name String
وكما تلاحظون أيضا أنه باستخدام هذه Function فإننا نعطي مستخدم البرنامج الأفضلية في اختيار وتحديد الصورة التي يريد إضافتها الي البرنامج آو الي الفورم
طبعا نفس الفكرة من الممكن استخدامها ليس فقط مع الصور ولكن يمكن استخدامها مع ملفات أخري أي أنك عزيزي القارئ يمكن أن تقوم بتطوير هذه Function وبالتالي تستخدمها كيفما شئت
و لقد قمت باستخدام Public Shared لأنني أنوي أن استخدم هذه Function في كلاس منفرد وذلك في أخر المقال
مثال علي استخدام Public Shared Function LoadImageFile()
ولتنفيذ المثال افتح مشروع جديد ثم أضف الي الفورم PictureBox و Button ثم استخدم الكود بالشكل التالي


كود :
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

Dim bmpFileName As String = LoadImageFile()
If bmpFileName Is Nothing Then Exit Sub
Dim bmp As Bitmap = New Bitmap(bmpFileName)

PictureBox1.Image = bmp
PictureBox1.SizeMode = PictureBoxSizeMode.CenterImage

End Sub

Public Shared Function LoadImageFile()

Dim ofd As New OpenFileDialog
With ofd
.Multiselect = False
.Filter = "All Files|*.*|Bitmaps|*.bmp|GIFs|*.gif|JPEGs|*.jpg|PNGs|*.png"
.FilterIndex = 4
.FileName = "Select image file"
End With

Dim bmpFile As String = ofd.FileName

If ofd.ShowDialog() <> DialogResult.OK Then
bmpFile = Nothing
Else
bmpFile = ofd.FileName

End If

LoadImageFile = bmpFile

End Function ' LoadImageFile Function

End Class



بالتوفيق
أخوكم عمر