الشبكة العربية لمطوري الألعاب

خبير مشرف مؤيد مارديني هذه المشاركة مميزة مشاركة 1

وضع شعار شركتك على الصور التي ينتجها برنامجك :
مثلاً : قمت بعمل برنامج رسم نسخة تجريبية فتجعل البرنامج يضع شعاره على الصور التي يحفظها.
إذا أردت استخدام الـ Class من ضمن المشروع فيكفي هذا الكود :
Dim InSt As New SealYourPics
InSt.Seal(PictureBoxSource.Image, _
PictureBoxLogo.Image, SealYourPics.Corner.Top_Left)
PictureBoxResult.Image = InSt.ResultPic

لتوضيح عمل الكلاس تماماً انظهر هذه الصورة

الآن الشروط المطلوبة في صورة الشعار : يجب أن يكون لون الخلفية
Red = 255
Green = 000
Blue = 255
و أي لون آخر غير هذا اللون سيظهر و يعتبر من الشعار , و يفضل أن يكون نوع صورة الشعار Bmp لأن بعض الأنواع الأخرى تشوه الألوان قليلاً..

و أخيراً كود الـ Class (فيجوال بيسيك .نيت) :
'Author : Moayad Mardini [moayad.m_at_gmail_dot_com]
'Forum : In|Structurez [http://www.agdn-online.com]
'IDE : Visual Studio .NET 2005 Professional
'Date : 02/12/2005
'Last Edit : 06/12/2005
Imports System.Drawing
Imports System.Math
Public Class SealYourPics
    Private Result As Bitmap
    Public ReadOnly Property ResultPic()
        Get
            Return Result
        End Get
    End Property
    Public Sub Seal(ByVal OrigianPicture As Bitmap, _
    ByVal CompanyLogo As Bitmap, ByVal DrawLogoCorner As Corner)
        Try
            Dim SourcePic As New Bitmap(OrigianPicture)
            Dim LogoPic As New Bitmap(CompanyLogo)
            Dim Temp As Integer, Temp2 As Integer
            Dim MinWidth As Integer = Min(LogoPic.Width, _
            SourcePic.Width)
            Dim MinHeight As Integer = Min(LogoPic.Height, _
            SourcePic.Height)
            Dim WidthPlus As Integer
            Dim HeightPlus As Integer
            Select Case DrawLogoCorner
                Case Corner.Bottom_Left
                    WidthPlus = 0
                    HeightPlus = SourcePic.Height - MinHeight
                Case Corner.Bottom_Right
                    WidthPlus = SourcePic.Width - MinWidth
                    HeightPlus = SourcePic.Height - MinHeight
                Case Corner.Top_Left
                    WidthPlus = 0
                    HeightPlus = 0
                Case Corner.Top_Right
                    WidthPlus = SourcePic.Width - MinWidth
                    HeightPlus = 0
            End Select
            For Temp = 0 To MinHeight - 1
                For Temp2 = 0 To MinWidth - 1
                    If LogoPic.GetPixel(Temp2, Temp).ToArgb <> -65281 Then
                        SourcePic.SetPixel(Temp2 + WidthPlus, _
                        Temp + HeightPlus, LogoPic.GetPixel(Temp2, Temp))
                    End If
                Next
            Next
            Result = New Bitmap(SourcePic)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub
    Public Enum Corner
        Top_Right
        Top_Left
        Bottom_Right
        Bottom_Left
    End Enum
End Class


أي سؤال أو اقتراح ؟
مؤيد مارديني

Moayad Mardini,
MSDN Forums Moderator

خبير مدير وسام البهنسي مشاركة 2

هاها. جميل جداً! أرى أنك بالفعل قمت بتنفيذ أحد اقتراحاتك بعرض صور المنتدى☺
تعليقات قد تكون غير ذات أهمية:
- الخطأ المذكور ينتج عند التعامل مع نوعية صور تستخدم palette (هل يستطيع أحد أن يساعدني في تعريف الـ palette؟).
- للأداء: يمكنك حفظ التعبير:
Min(LogoPic.Width, SourcePic.Width) – 1

والتعبير:
Min(LogoPic.Height, SourcePic.Height) - 1

في متغيرات جانبية لتفادي حساب هذه القيمة عند كل سطر وعمود، وهو أمر مكلف بالنسبة للصور الكبيرة.
- قد يكون من الأسرع تفادي استخدام GetHashCode() على لون البكسل ثم مقارنته. غالباً المقارنة المباشرة مع العناصر اللونية ذاتها (الأحمر والأخضر والأصفر) ستكون أكثر وضوحاً وأسرع.

اقتراح:
يمكنك إضافة option للـ class لجعله يدعم توضيع الشعار في أي من الزوايا الأربع للصورة.

وسام البهنسي
مبرمج في إنفيديا وإنفريمز

محترف مشرف عبد اللطيف حاجي علي مشاركة 3

اقتراح آخر للأداء: أعتقد أنه من الأفضل عكس طريقة الـ looping على الـ pixels، أي المرور على الأسطر بدلاً من الأعمدة (على اعتبار أن الـ pixels تخزن سطر بعد سطر وليس عمود بعد عمود) مما يؤدي إلى زيادة الأداء بشكل ملحوظ (على الأقل على الصور الكبيرة) لأن الذاكرة ستقرأ بالتالي بالتسلسل (دون قفز)
أيضاً، *شخصيا*ً لا أحبذ فكرة حفظ الصورة الناتجة في ملف مختلف، فغالباً ما سيحتاج المسنخدم لاستخدامها فوراً مما يضطره لفتح الصورة مرة أخرى و بالتالي ضياعٌ في الأداء، ولكن لم لا يكون هناك إجراءان الأول يعود بـ Bitmap Object و الآخر (مستخدمأ الأول) يقوم بحفظها في File، هكذا تمنح المستخدم حرية الاختيار (و تبرر استخدام الـ class من أجل أجراء واحد)
أخيراً، ما هو عمل oGraphics؟ أرى أنك تنشئه دون أن تستخدمه حقاً...

بالنسبة للـ palette فهي طريقة قديمة لحفظ الألوان استخدمت في العهد القديم قبل اكتشاف دارات السيليكون الرخيصة، حيث كانت الذاكرة محدودة و باهظة الثمن، لذلك لم يكن بمقدور المبرمج الحجري أن يحفظ الصورة كما هي في الذاكرة (كل pixel له لونه الخاص في مكانه الخاص) لذلك اخترع هذه الطريقة التي يقوم فيها بحفظ الألوان الأكثر استخداماً في الصورة في جدول (بحيث أن كل لون يُمثل بالـ index الخاص به فقط، والذي يتراوح من الصفر إلى 255، أي يحتاج إلى بايت واحد فقط) كما تلاحظ فإن باستطاعته تمثيل ألوان معقدة (و إن كانت محدودة) تحتاج في الحالات العادية إلى 4 بايتات مثلاً ببايت واحد فقط (بدون حساب حجم الـ palette طبعاً, على اعتبار أنه ثابت مهما كانت أبعاد الصورة)... بالطبع, يجب خفض دقة الصورة بحيث تمثل بـ 256 لوناً فقط... وكما قال SetPixel فإن هذه الطريقة انقرضت تقريباً الآن، لذلك فكثير من الإجراءات و الخوارزميات لا تأخذها بعين الاعتبار

عبد اللطيف حاجي علي
مبرمج
In|Framez

خبير مشرف مؤيد مارديني مشاركة 4

شكراً لكما,
قمت بتنفيذ اقتراحاتكما , و بالنسبة لاختيار الزاوية أضفت باراميتر جديد يأخد القيم :
Top_Right
Top_Left
Bottom_Right
Bottom_Left

و أما اقتراح أن يوضع الشعار على نفس الصورة الأصلية مباشرةً فالآن يمكن أن يكون ذلك بأن يكون الباراميتر ResultPicturePath يساوي OrigianPicturePath و سينفذ بدون أي مشاكل.

و بالنسبة لعدم استخدام SetPixel فما هو البديل لها و ما هي مميزاته عنها ؟


شكراً,
Moayad Mardini

Moayad Mardini,
MSDN Forums Moderator

محترف مشرف عبد اللطيف حاجي علي مشاركة 5

التعليق على مشاركة مؤيد مارديني في Dec 3, 2005 15:37 :

> شكراً لكما,
> قمت بتنفيذ اقتراحاتكما , و بالنسبة لاختيار
> الزاوية أضفت باراميتر جديد يأخد القيم :
جيد جداً... مع أنه يمكنك ضغط الإجراء بحيث لا تحتاج لتكرار الـ loop من أجل كل حالة. تستطيع أن تجعل تغيير توضع الصورة يؤدي فقط إلى تغيير بعض المتغيرات الداخلية (أسرع و أجمل)

> أما اقتراح أن يوضع الشعار على نفس الصورة الأصلية مباشرةً
> فالآن يمكن أن يكون ذلك بأن يكون الباراميتر ResultPicturePath
> يساوي OrigianPicturePath و سينفذ بدون أي مشاكل.
أخشى أن تكون قد أخطأت فهمي. أنا لم أقترح أن يتم حفظ الصورة بنفس اسم الملف السابق، بل اقترحت ألا يتم حفظها أبداً! بل إعادة Object الصورة المعدل كما هو، لأنه و كما قلت فإن المستخدم غالباً سيقوم باستخدام الصورة مباشرةً (على الأقل في تطبيقات الـ Real-time)

> بالنسبة لعدم استخدام SetPixel فما هو البديل لها و ما
> هي مميزاته عنها ؟
مرة أخرى، أخشى أن تكون قد أخطأت فهمي! أنا لم اقترح عدم استخدام SetPixel، على العكس ،أنا قلت فقط إن نظام الـ palette قد انقرض (تقريباً) ولا داعي لأخذه بعين الاعتبار في اجراءك (برأيي الشخصي).

عبد اللطيف حاجي علي
مبرمج
In|Framez

خبير مشرف مؤيد مارديني مشاركة 6

التعليق على مشاركة Abdo Haji-Ali في Dec 3, 2005 21:4 :

> أنا لم أقترح أن يتم حفظ الصورة بنفس اسم الملف السابق،
> بل اقترحت ألا يتم حفظها أبداً! بل إعادة Object الصورة
> المعدل كما هو، لأنه و كما قلت فإن المستخدم غالباً سيقوم
> باستخدام الصورة مباشرةً (على الأقل في تطبيقات الـ Real-time)

الآن قلت الباراميترات المستخدمة !
أصبحت :
OrigianPicture من النوع Bitmap
CompanyLogo من النوع Bitmap
DrawLogoCorner من النوع Corner

و بالنسبة للنتيجة فهي الخاصية ResultPic من النسخة التي أنشأتها من النوع Bitmap أيضاً☺
أي مثلاً :
Dim InSt As New SealYourPics(PictureBoxSourcePic.Image, _
PictureBoxLogo.Image, SealYourPics.Corner.Top_Right)
PictureBoxResult.Image = InSt.ResultPic

قمت بتعديل المشاركة الأولى تعديل جذري لتتناسب مع التغيرات !

شكراً ,
مؤيد مارديني

Moayad Mardini,
MSDN Forums Moderator

محترف مشرف عبد اللطيف حاجي علي مشاركة 7

لا أريد أن أبدو لحوحاً أو متطلباً... لكن بما أنك تستخدم لغة .NET و التي من المفترض أن تكون أكثر اللغات Object Oriented حتى الآن، لم لا تستخدم مميزات اللغة في تصميم الـ classes.
استخدام هذه المميزات (بحكمة) يضمن الأمن (مثلاً إذا جعلت ResultPic للقراءة فقط، لن تسمح للمستخدم بتغيير الصورة الناتجة كما يشاء), كما أنه يزيد من امكانية استخدام الـ code أكثر من مرة (Portability) وأخيراً و ليس آخراً فإنه (برأيي) يضفي طابع الاحترافية على الـ code...

عبد اللطيف حاجي علي
مبرمج
In|Framez

خبير مشرف مؤيد مارديني مشاركة 8

التعليق على مشاركة Abdo Haji-Ali في Dec 5, 2005 21:12 :

> لا أريد أن أبدو لحوحاً أو متطلباً...
على العكس تماماً , هذه الاقتراحات هي التي تفيدني و تساعد على تحسين الـ Class☺

> استخدام هذه المميزات (بحكمة) يضمن الأمن
> (مثلاً إذا جعلت ResultPic للقراءة فقط، لن تسمح للمستخدم
> بتغيير الصورة الناتجة كما يشاء) كما أنه يزيد من امكانية
> استخدام الـ code أكثر من مرة (Portability)

نعم , جعلت هذه الخاصية للقراءة فقط (Read-Only) , و عند قراءة الخاصية تعيد باستخدام التعبير (Return) قيمة متغير خاص و الذي يحمل الاسم Result

ملاحظة : الآن تنفذ عملية وضع الشعار ليس عندما يتم إنشاء نسخة جديدة من الكلاس :
Dim VR As New SealYourPics (...)

و إنما عند استدعاء :
Dim VR As New SealYourPics
VR.Seal (...)

جزيل الشكر,
مؤيد مارديني

Moayad Mardini,
MSDN Forums Moderator