• 0
مصطفى 36a2

Project مشروع الكتابة باللغة العربية

سؤال

السلام عليكم ورحمة الله وبركاته
 
هدف المشروع :
كتابة كود أسمبلي مستقل عن نظام التشغيل يمكنه تلقي الدخل من المستخدم وكتابة الحرف العربي الموافق على الشاشة
خوارزمية كتابة الكود :
قد يبدو عنوان الفقرة غريباً , إلا أننا سنعمل على كتابة كود بلغة ++C سيقوم يتوليد كود الأسمبلي أو جزء منه على الأقل .
 
ولذلك سنعمل وفق الخطوات التالية :
1- تصميم الحروف العربية وتخزينها في ملف bmp ..
2- كود بلغة عالية المستوى سيقوم بقراءة كل حرف وتخزينه في مصفوفة خاصة
3- كود بلغة عالية المستوى سيقوم بتحويل محتوى المصفوفة إلى بايتات مخصصة لكود الأسمبلي
4- كود بلغة الأسمبلي سيقوم بقراءة الحرف من المستخدم وطباعة المصفوفة المخزنة فيه على الشاشة حسب الحرف الموافق
 
وسأبدأ بتفصيل كل خطوة على حدة :
1- تصميم الحروف العربية وتخزينها في ملف bmp ..
تمت كتابة المسودة سابقاً ولكن أثناء إجراء بعض التجارب وصلت إلى أبسط طريقة توفّر على المصمم وعلى المبرمج وهي واضحة في الصورة التالية
post-256536-0-74553300-1392383109_thumb.
test.bmp
قمت في الصورة التالية باستعارة حروف الخط Arial , في حال أردنا تصميم الخط بنفسنا فيجب مراعاة كون نقاط اتصال الحرف مع الذي قبله وبعده على نفس السطر (باختصار هناك خط يتوسط السطر دوماً وتتموضع عليه جميع نقاط الاتصال)
2- كود بلغة عالية المستوى سيقوم بقراءة كل حرف وتخزينه في مصفوفة خاصة
سيقوم الكود أولاً بقراءة الصورة الكبيرة ومن ثم تجزئتها إلى حروف
وحتى لا تتعقد خوارزمية استخراج كل حرف على حدة من الصورة , سنعتمد وضع علامة محددة في لوحة الصور وهي اللون الأحمر الفاقع RGB=0xFF0000 عند بداية ونهاية الحرف
وبذلك تكون الصورة كما يلي:
post-256536-0-53173400-1392383165_thumb.
test2.bmp
قمت بكتابة الكود التالي والذي يتعامل مع صور من النوع المذكور للتو , ويفصل الحروف ويخزنها في مصفوفات لكل حرف ..
هذا هو الكود :
 

#include <cstdio>#include <cstdlib>#include <conio.h>unsigned char **Letter[3];int hight,width;int GetLetters(){    int start;    int i,j,q,l;    FILE*bmp=fopen("C:\\Users\\Mostafa36a2\\Downloads\\My alphabet\\test2.bmp","rb");//put here the path        fseek(bmp,10,SEEK_SET);fread((void *)&start, sizeof(int), 1, bmp);        fseek(bmp,18,SEEK_SET);fread((void *)&width, sizeof(int), 1, bmp);        fseek(bmp,22,SEEK_SET);fread((void *)&hight, sizeof(int), 1, bmp);        fseek(bmp,start,SEEK_SET);        printf("%d %d %d\n",start,width,hight);        Letter[0]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[1]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[2]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        for(    i=hight-1   ;   i>=0  ; i--)        {            Letter[0][i]=(unsigned char *)malloc(width);            Letter[1][i]=(unsigned char *)malloc(width);            Letter[2][i]=(unsigned char *)malloc(width);            for(    j=0 ;   j<width ;       j++)            {                Letter[0][i][j]=fgetc(bmp);                Letter[1][i][j]=fgetc(bmp);                Letter[2][i][j]=fgetc(bmp);                /*int b=int((unsigned char))                ,g=int((unsigned char)fgetc(bmp))                ,r=int((unsigned char)fgetc(bmp))                ;*/                //printf("%d %d %d\n",r,g,b);                //Letter[i][j]=(r!=0xFF&&g!=0xFF&&b!=0xFF)?(1):0;            }            fread((void *)&l,1,width%4,bmp);        }        fclose(bmp);        for(i=0;i<hight;i++,putchar(10))            for(j=0;j<width;j++)                putchar(Letter[0][i][j]!=0xFF);    return 0;}const int NumberOfLetters=28;const int NumberOfStates=4;const int RGBColors=3;const int MaxLength=64;const int MaxWidth=64;unsigned char ExtractedLetters[RGBColors][NumberOfLetters][NumberOfStates][MaxLength][MaxWidth];//Yes , why not :)int main(){    GetLetters();    bool Save=false;    int letter=0;    int state=0;    int StartWidth;    for(int j=width-1;j>=0;j--)        {            for(int i=0;i<hight;i++)            {                if(Letter[2][i][j]==0xFF&&Letter[1][i][j]==0x00&&Letter[0][i][j]==0x00)//red                {                    puts("Hello");                    if(Save==0){                        puts("Start");                        StartWidth=j;                        Save=1;                        break;                    }else{                        puts("End");                    printf("%d\t%d\t%d\n",j+1,StartWidth,letter);                        for(int q=0;q<hight;q++){                            for(int k=j+1;k<StartWidth;k++){//remember the we move left                                    for(int rgb=0;rgb<3;rgb++){                                        ExtractedLetters[rgb][letter][state][q][k-StartWidth]=Letter[rgb][q][k];                                    }putchar(Letter[0][q][k]!=0xFF);                                }putchar(10);                        }                        state=(state+1)%4;                        if(state==0)                            letter++;                        Save=0;                        break;                    }                }            }        }    return 0;}

 
من يرغب في التعقيد فيمكنه استخدام هذا الكود لاستخراج الحروف حرفاً حرفاً بشكل يدوي .. (بالأسهم )
يحتاج إلى تكملة ولكن لن أقوم بها :)
 

#include <cstdio>#include <cstdlib>#include <conio.h>unsigned char **Letter[3];int hight,width;int GetLetters(){    int start;    int i,j,q,l;    FILE*bmp=fopen("C:\\Users\\Mostafa36a2\\Downloads\\My alphabet\\test.bmp","rb");//put here the path        fseek(bmp,10,SEEK_SET);fread((void *)&start, sizeof(int), 1, bmp);        fseek(bmp,18,SEEK_SET);fread((void *)&width, sizeof(int), 1, bmp);        fseek(bmp,22,SEEK_SET);fread((void *)&hight, sizeof(int), 1, bmp);        fseek(bmp,start,SEEK_SET);        printf("%d %d %d\n",start,width,hight);        Letter[0]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[1]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        Letter[2]=(unsigned char**)malloc(hight*sizeof(unsigned char*));        for(    i=hight-1   ;   i>=0  ; i--)        {            Letter[0][i]=(unsigned char *)malloc(width);            Letter[1][i]=(unsigned char *)malloc(width);            Letter[2][i]=(unsigned char *)malloc(width);            for(    j=0 ;   j<width ;       j++)            {                Letter[0][i][j]=fgetc(bmp);                Letter[1][i][j]=fgetc(bmp);                Letter[2][i][j]=fgetc(bmp);                /*int b=int((unsigned char))                ,g=int((unsigned char)fgetc(bmp))                ,r=int((unsigned char)fgetc(bmp))                ;*/                //printf("%d %d %d\n",r,g,b);                //Letter[i][j]=(r!=0xFF&&g!=0xFF&&b!=0xFF)?(1):0;            }            fread((void *)&l,1,width%4,bmp);        }        fclose(bmp);        for(i=0;i<hight;i++,putchar(10))            for(j=0;j<width;j++)                putchar(Letter[0][i][j]!=0xFF);    return 0;}int main(){    GetLetters();    int start=0;    for(int j=0;;)    {        for(int i=0;i<hight;i++,puts("|"))            for(int k=width-1-start;k>=0&&k>=width-1-j;k--)                putchar(Letter[0][i][k]!=0xFF);        int b;        if((b=getch())==224){                switch(b=getch()){                    case 72:puts("up");break;                    case 75:puts("left");j--;break;                    case 77:puts("right");j++;break;                    case 80:puts("down");break;                    default :printf("%d\n",b);                };        }        else        {            switch (b){                case ' ':start=j;break;            }        }            printf("---%d\n",b);    }    return 0;}

 
3- كود بلغة عالية المستوى سيقوم بتحويل محتوى المصفوفة إلى بايتات مخصصة لكود الأسمبلي
خوارزمية تنظيم كود الأسمبلي الخاص بالمشروع :
حتى الآن يمكننا طباعة الحروف بكامل الدقة مع الظلال المخزنة ( لدينا 24بت لوني لكل بكسل )
سنقوم بتخزين 3 قيم لكل حرف :
1- عنوان مصفوفة الحرف
2- عرض المصفوفة
3- طول المصفوفة
وسنقوم بتخزين عدد من البتات لكل بكسل يتناسب مع عدد الألوان التي سنختارها
إن اخترنا الأبيض والأسود يمكننا تخزين كل بكسل في بت واحد .. ولكن على حساب بعض التعقيد في كود استخراج البكسل
على كل حال سنستخدم بايت واحد سواء سنستعمل الأبيض والأسود أم 256 لوناً (أقصى ما يدعمه نمط العرض الذي سنستخدمه )
 
سنحتاج إلى مصفوفة خاصة لتخزين عناوين الحروف بحيث تكون منظمة بشكل ما (سنختار وجود الأشكال المتعددة لنفس الحرف بحيث تكون متتالية )
وعند الوصول إلى الحرف سيكون أول بايتين فيه هما الطول والعرض على التتالي
ويبقى ما تبقّى من الكود خاص بتحديد شكل الحرف المطلوب رسمه وفق الدخل المعطى , وتحديد مكان رسم الحرف (مكان المؤشر)
 
من الواضح الآن (حسب ظني) أن كتابة هذا الجزء غاية في البساطة (اعتماداً على الجزء السابق)
فكل ما علينا هو طباعة البكسلات بشكل رقمي وأن نسبقها بالطول والعرض
وأن نطبع عناوين الحروف بشكل متتالي ,
فعلياً سنقوم بطباعة الـoffset فقط كما يلي:
الحرف الأول عنوانه 0 , والحرف الثاني عنوانه 0+عدد بكسلات الحرف الأول +2 (2 هي بايتان للطول والعرض)
 
(التطبيق مع الشرح سنتابعه في قسم الأسمبلي إن شاء الله لاحقاً)
 
4- كود بلغة الأسمبلي سيقوم بقراءة الحرف من المستخدم وطباعة المصفوفة المخزنة فيه على الشاشة حسب الحرف الموافق
سنقوم أولاً بإنهاء الكود هنا والتأكد من صحة الخوارزمية المتبعة قبل تحويل الكود إلى أسمبلي ..(هنا في الردود القادمة بإذن الله)
خوارزمية معرفة الحرف المناسب : ببساطة مصفوفة تقوم بعمل mapping من ترميز الآسكي الخاص بالزر المضغوط إلى رقم الحرف في المصفوفة
خوارزمية طباعة الحرف  تتمثل في عمل حلقتين متداخلتين وطباعة الحرف بكسلاً بكسلاً في الموضع الذي يحدده المؤشر
خوارزمية تحريك المؤشر  .. بعد كل حرف نضيف واحد , وعند الوصول إلى أقصى عدد ممكن من الحروف في الشاشة ننزل سطراً ونرجع المؤشر للبداية , وهناك بعض الأزرار الخاصة مثل backspaceو space و enter و tab التي لها تأثير خاص على المؤشر . ويمكن لنا أن نضيف العديد منها بسهولة
خوارزمية اختيار الشكل المناسب للحرف
هنا جوهر الكتابة بالعربية , حيث يتغير شكل الحرف السابق والحالي حسب الحرف السابق وفق القواعد التالي
1- الحرف السابق لا يمكن أن يتصل من اليسار : عندها نطبع الحرف بالشكل 0 (المنفصل )
2- الحرف السابق يمكن أن يتصل من اليسار : (ملاحظة : جميع الحروف يمكن أن تتصل من اليمين عدا الهمزة على السطر "ء" )
    1- الحرف السابق في شكله المنفصل : انتقل للشكل المتصل من اليسار
    2- الحرف السابق في شكله المتصل من اليمين : انتقل للشكل المتصل من الجانبين
ملاحظات على الخوارزمية :
1- نلاحظ أن علينا الاحتفاظ بالحرف السابق وحالته ,ولكن بسبب إمكانية محي الحروف backspace سنحتاج إلى حفظ قائمة بجميع الحروف المكتوبة وألا نكتفي فقط بطباعتها
2- نلاحظ أيضاً أن علينا الاحتفاظ بقائمة تبيّن نوع الحرف (هل يتصل من اليسار أم لا ) , وبالمناسبة هناك نوعان للحروف : الأول يمكن أن يتصل من اليسار والثاني لا , (وتشذّ عن الثاعدة الهمزة "ء" فهي دوماً بالشكل المنفصل)

 

 

والله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

1 إجابات على هذا السؤال .

  • 0

السلام عليكم ..

انتهيت من الكود شبه المكتمل

تجدونه في المرفقات مع ملف تنفيذي خاص للتجربة ..

(أعتذر لأنني سأتغيب في الأسبوع القادم عن المنتدى .. من لديه القدرة والرغبة على تطوير المشروع فليعمل عليه )

في الأسبوع القادم تقريباً سنبدأ الشق الأسمبلاوي من المشروع

 

والله ولي التوفيق

0x36a2.rar

تم تعديل بواسطه مصطفى 36a2
تعديل ملف exe في المرفق
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .