رسم المتجهات بواسطة بوست سكريبت (PostScript)
نشر في Oct 14, 2020 بقلم السيد مذهل.
قائمة المحتويات
ما هو بوست سكريبت (Post Script) ولماذا؟
لغة برمحة أو صيغة بوست سكريبت (PostScript) هي لغة برمجة بسيطة لنطاق معين (domain-specific language (DSL)) وهو رسم المتجهات وما نعني بالمتجهات (Vector graphics) هي الصور التي ترسم بصيغة وصفية حيث مهما قمنا بتكبير الصورة لن تفقد جودتها على عكس الصور والرسوميات النقطية (Pixel-based) والعديد من المحررات وأدوات الرسم الرسومية قادرة على كتابة وتصدير هذه الصيغة ومنها أنكسكيب (Inkscape) و جيمب (Gimp) وغيرها الكثير الكثير.
ولكن ما دام بوست سكريبت مدعوماً من العديد من البرامج الرسومية لماذا نتعلمه إذاً؟
هذا سؤال وجيه وللأجابة عنه نستطيع أن نقول أن نموذج رسم بوست سكريبت (PostScript drawing model) نموذج منتشر بشكل كبير جداً بحيث أن حتى مكتبة GTK+3 الشهيرة للتطوير الواجهات الرسومبة تستخدم هذا النموذج لرسم القطعة الخاصة التي يطور المبرمج (Custom widgets) وهذه الصيغة مدعومة من كل الطابعات الحديثة وتتيح لنا رسم الأشكال البسيطة دون الحاجة للدخول لبرنامج متخصص برسم المتجهات كأنكسكيب أو رسم الأشكال التي تحتاج عمليات تكرارية وهندسة وما إلى هنالك مع العلم بأن أحد أهداف هذه المدونة المتواضعة هو طرح مواضيع متعلقة برسوميات الحاسوب وبرمجة هندسة الصوتيات.
الأدوات اللازمة
لأستخدام بوست سكريبت سنحتاج إلى تثبيت مفسر اللغة (Language interpreter) وهنا سنستخدم نسخة حرة وشهيرة تسمى Ghostscript ويمكن تنزيله من الموقع الرسمي والرجوع للوثائق رغم أن تثبيت غير لازم لأننا نستيطع أستخدام جيمب وأنكسكيب اللذان يملكان نسخة مضمنة فيهما من ما يتيح لهما فتح هكذا نوع من الملفات.
مستخدمين ويندوز يستطيع تنزيل المثبت وحتى مستخدمين التوزيعات الجناوية (GNU/Linux distributions) ولكن يفضل تنزيله من المستودعات الرسمية:
آرتش ومشتقاتها:
$ sudo pacman -S ghostscript
دبيان ومشتقاتها:
$ sudo apt-get install ghostscript
جنتو ومشتقاتها:
$ sudo emerge --ask app-text/ghostscript-gpl
ردهات وفيدورا ومشتقاتهما:
$ sudo dnf install ghostscript
وأما مستخدمين الماك فبأمكانهم أتباع هذا الشرح أو بناء الشفرة المصدرية وهذا قد يكون شيء جديد على بعض القراء لذلك لن أشرحه ولكن أضع ملاحظة صغيرة مفادها أن بناء الشفرة المصدرية للبرمجيات أسهل في أغلب الحالات عند أستخدام التوزيعات الجناوية ويليها الماك والأصعب هو ويندوز بالأخص إذا كان البرنامج متعدد الأنظمة وغير مخصص لويندوز.
ولإنشاء ملفات بوست سكريبت يمكننا أستخدام إي محرر نصوص وفي حالتي سوف أستخدام إيماكس لأنه يلون الشفرة المصدرية وفيه أختصار لعرض الرسم وكل هذا وزيادة دون إضافات ولكن بشرط توفر Ghostscript مثبت.
لنرسم
%! %% comment line 50 50 moveto 200 200 lineto stroke showpage
أحفظ هذا النص داخل ملف drawing.ps
وقم بإدخال هذا السطر الأتي في الطرفية (commandline):
للمبتدئين: عندما ترى علامة الدولار $ في الأوامر التي أنشرها لا تنسخها مع الأمر لأنها دلالة على أن الأمر يشغل كمستخدم عادي الصلاحيات
$ gs -dSAFER -dBATCH -dNOPAUSE -sDEVICE=png16m -dGraphicsAlphaBits=4 -sOutputFile=drawing.png drawing.ps
وستكون النتيجة رسم خط بالعرض الأفتراضي.
شكل 1: شاشة الضبط
أو يمكنك أستخدام إيماكس لعرض وتعديل ملف بوست سكريبت كما هو موضح بالصورة المتحركة أدناه:
شكل 2: صورة متحركة توضح طريقة أستخدام إيماكس لعرض وتعديل ملفات بوست سكريبت
للأنتقال من وضع العرض لوضع التعديل والعكس أستعمل هذا الأختصار C-c
C-c
وإيضاً هناك خيار خياران آخران أولهما هو فتح الملف بأستخدام برنامج يدعم صيغة بوست سكريبت كجيمب (Gimp) والآخر هو أستخدام المفسر (Interpreter) الذي يأتي مع ghostscript وهو gsx:
شكل 3: طريقة أستخدام المفسر
مع العلم أن حجم الصفحة الأفتراضي يعتمد على النظام واللغة والبلد في حاسوبك ففي الكثير من الأحيان هو A4 ولكن ليس دوماً.
وأما الأن لنتفرغ لشرح ما جرى:
شكل 4: طريقة الترتيب العكسي
أولاً بوست سكريبت يستخدم طريقة الترتيب العكسي (Postfix) بحيث يضع خيارات الدالة (Function arguments) قبل أسم الدالة بدون أقواس وثانياً لا يمكننا أستخدام lineto
أو curveto
دون تحديد والترحك لموقع معين بأستخدام moveto
التي تأخذ الأحداثيات x,y وثالثاً إذا لم تستعمل showpage
إي أظهر الصفحة فلا شيء سيظهر وهذا أبسط مثال فبعدها ننتقل لنتعلم الدوال الشائعة الآخرى عبر الأمثلة.
نظام الأحداثيات في بوست سكريبت يبدأ من الزاوية اليسرى السفلى (وهنا أختلاف بينه وبين libcairo التي تبدأ من الزاوية اليسرى العلوية) واليمين هو محور x الموجب والأعلى هو محور y الموجب وما عكسهما هو السالب.
شكل 5: نظام أحداثيات بوست سكريبت
المثال الثاني:
% draw triangle 100 200 moveto 200 250 lineto 100 300 lineto closepath gsave 0.5 0.5 1 setrgbcolor fill grestore 10 setlinewidth stroke % draw unfilled rectangle 200 100 100 100 rectstroke stroke % draw filled unstroke rectangle gsave 1 0 1 setrgbcolor 240 210 100 100 rectfill stroke grestore % draw not completed circle (arc) 120 370 60 0 350 arc stroke showpage
شكل 6: المثال الثاني
لتوضيح بعض النقاط بالمثال الثاني:
- أولاً عندما كنا نرسم المثلث لم نقم بوضع الأحداثيات للنقطة الأخيرة بل أستعملنا دالة
closepath
لغلق المسار وبعدها لم نقم برسم الخط مباشرة ولا ملء الشكل بإي لون مباشرة لأننا لو قمنا بأحد هذه العمليات سنفقد السيطرة على الشكل فلا يمكن ملء الشكل وبعدها رسم الخط بأستخدامstroke
مباشرة لذلك أحتجنا لأن نحفظ الحالة (state) بأستخدامgsave
وgrestore
ومن ثمة غيرنا اللون عبرsetrgbcolor
التي تأخذ قيم الألوان أحمر - أخضر - أزرق بالترتيب وبقيم كسرية ما بين الصفر والواحد وملأنا الشكل وبعدها عدنا للحالة الأولى ورسمنا الخطstroke
. - ثانياً وضحنا طريقة أستخدام دالتين لرسم مستطيل وفي حالتنا كان المستطيل متوازي الأضلاع (مربع) وإيضاً وضحنا كيفية أستخدام دالة القوس
arc
ورسمنا بها دائرة غير مكتملة وهذه نماذج الدوال المذكورة:
x y radius angle1 angle2 arch
x y width height rectfill
x y width height rectstroke
المثال الأتي يشرح أنواع أغطية المسارات والوصلات وكيفية أستخدام الخطوط:
ملاحظة: لم أكتب النص بالمثال باللغة العربية لأن بوست سكريبت لا يدعمها وسنتكلم عن هذا لأحقاً في قسم ماذا بعد
/Times-Roman findfont 20 scalefont setfont newpath 100 200 moveto (Happy, ) show /Helvetica-BoldOblique findfont 20 scalefont setfont newpath 160 200 moveto (Hacking) show %% 1st linecap demo 100 100 moveto 100 0 rlineto 0 setgray 10 setlinewidth 0 setlinecap %% Focus here stroke 100 100 moveto 100 0 rlineto 1 setgray 1 setlinewidth stroke %% 2nd linecap demo 100 80 moveto 100 0 rlineto 0 setgray 10 setlinewidth 1 setlinecap %% Focus here stroke 100 80 moveto 100 0 rlineto 1 setgray 1 setlinewidth stroke %% 3rd linecap demo 100 60 moveto 100 0 rlineto 0 setgray 10 setlinewidth 2 setlinecap %% Focus here stroke 100 60 moveto 100 0 rlineto 1 setgray 1 setlinewidth stroke 0 setlinecap % rest to default line cap style, this could be avoided % by saving state with gsave, grestore %%%%%%%%%%%%%%%%%%%%%%% 0 setgray 10 setlinewidth %% 1st line joint style 280 220 moveto 70 0 rlineto -70 70 rlineto 0 setlinejoin %% Focus here stroke %% 2nd line joint style 280 130 moveto 70 0 rlineto -70 70 rlineto 1 setlinejoin %% Focus here stroke %% 3rd line joint style 280 35 moveto 70 0 rlineto -70 70 rlineto 2 setlinejoin %% Focus here stroke showpage
شكل 7: المثال الثالث
الجدير بالذكر بالمثال أعلاه هو أستهخدامنا للأحداثيات المجاورة للنقطة الحالية بمعنى أن أنتقلنا أو سقنا خطاً للنقطة (100,100) وأستخدمنا rlineto
بقيم x = 100 و y = 0 فهذا يعني تقدمنا مائة نقطة نحو محور x بالموجب فيكون موقعنا الدقيق حينها x = 200 و y = 100 مع العلم أن النقطة الواحدة ببوست سكريبت تمثل 1/72 بوصة (inch) وملاحظة هامة أخرى يجب الأنتباه لها هو أننا نكتب كل أمر في سطر وهذا لتسهيل قراءة الشفرة المصدرية ولكن هذا غير لازم فيسعنا أن نكتب كل الأوامر بسطر واحد أو أثنين.
إذا كنت تستخدم إيماكس وكنت تعدل ملف بوست سكريبت وأنت في وضع التعديل لا العرض يمكنك الذهاب للقائمة العلوية:
PostScript
> Fonts (1)
أو
PostScript
> Fonts (2)
لتجد قائمة بالخطوط المثبتة لبوست سكريبت في نظامك وهذه مجموعات الخطوطات الأساسية التي تأتي مع ghostscript:
* Fonts (1) 1) Times-Roman 2) Times-Bold 3) Times-Italic 4) Times-BoldItalic 5) Helvetica 6) Helvetica-Bold 7) Helvetica-Oblique 8) Helvetica-BoldOblique 9) Courier 10) Courier-Bold 11) Courier-Oblique 12) Courier-BoldOblique 13) Symbol * Fonts (2) 1) AvantGarde-Book 2) AvantGarde-Demi 3) AvantGarde-BookOblique 4) AvantGarde-DemiOblique 5) Bookman-Light 6) Bookman-Demi 7) Bookman-LightItalic 8) Bookman-DemiItalic 9) Helvetica-Narrow 10) Helvetica-Narrow-Bold 11) Helvetica-Narrow-Oblique 12) Helvetica-Narrow-BoldOblique 13) NewCenturySchlbk-Roman 14) NewCenturySchlbk-Bold 15) NewCenturySchlbk-Italic 16) NewCenturySchlbk-BoldItalic 17) Palatino-Roman 18) Palatino-Bold 19) Palatino-Italic 20) Palatino-BoldItalic 21) ZapfChancery-MediumItalic 22) ZapfDingbats
هنا نوضح طريقة برمجة دالة تأخذ معطيات وأخرى لا تأخذ وإيضاً كيف نستخدم الحلقات التكرارية (loops):
/myshape { 0 0 moveto -15 0 rlineto -15 10 -15 90 -5 100 rcurveto 0 10 rlineto -5 0 rlineto 0 10 rlineto 25 0 rlineto 0 -10 rlineto -5 0 rlineto 0 -10 rlineto 15 -10 15 -90 5 -100 rcurveto stroke } def /myshape_plus { /blue exch def /green exch def /red exch def gsave 0 0 moveto -15 0 rlineto -15 10 -15 90 -5 100 rcurveto 0 10 rlineto -5 0 rlineto 0 10 rlineto 25 0 rlineto 0 -10 rlineto -5 0 rlineto 0 -10 rlineto 15 -10 15 -90 5 -100 rcurveto gsave red green blue setrgbcolor fill grestore stroke grestore } def 100 100 translate myshape 100 0 translate 1 0 0 myshape_plus -40 180 translate 0 1 9 { /iter exch def iter 4 mul rotate 30 30 translate myshape } for 0 1 9 { /iter exch def iter 4 mul rotate 30 30 translate 0 1 0 myshape_plus } for showpage
شكل 8: نتيجة الدوال والدورة
بمثالنا أعلاه قمنا بتعريف دالتين كما مبين بالشفرة وهما myshape
و myshape_plus
وكما نلاحظ أن الأولى لا تأخذ عوامل وما فيها مجرد سرد لخطوات رسم المزهرية وأما الثانية تأخذ عوامل (Function arguments) وما يجب ملاحظته هنا هو أن العوامل بتعريف الدالة يجب أن تكتب بشكل عكسي وبالنسبة لتوضيح أستعمال الدورة (loop) فالقيم المعطاة كالأتي (القيم الأولية - الزبادة أو النقصان - الحد أو القيمة النهاية) ويوضع جسد الدورة داخل الأقواس العرجاء {}
وبعدها مفردة for
.
من الملاحظ أستعمالنا بالمثال السابق لعملية الضرب الرياضية mul
التي تأخذ عددين فقط للضرب كعوامل وهكذا بقية العمليات الرياضية مثل الجمع add
والطرح sub
والقسمة div
.
لا ننسى أستخدامنا لدالة الإزاحة translate
وهذه الدالة تختلف عن دالة التحرك moveto
ويمكن توضيحها وأخواتها من scale
و rotate
كما يلي:
شكل 9: سحب وتدوير وتحجيم المحور
مع العلم أن القيم الكسرية التي هي أقل من واحد تصغر المحور وما هو أكبر من واحد يكبر المحور في دالة التحجيم scale
ودالة rotate
تأخذ قيمة زاوية تتراوح ما بين 0 إلى 360 درجة فإذا كانت القيمة موجبة سيتم الدوران على عكس عقارب الساعة بينما إذا كانت سالبة سيتم الدوران حول عقارب الساعة.
الجمل الشرطية (if statement) والمتغيرات ذات النطاق المحلي (local variables) وكيفية تعريف متغير (variable):
/myshape { 0 0 moveto -15 0 rlineto -15 10 -15 90 -5 100 rcurveto 0 10 rlineto -5 0 rlineto 0 10 rlineto 25 0 rlineto 0 -10 rlineto -5 0 rlineto 0 -10 rlineto 15 -10 15 -90 5 -100 rcurveto stroke } def /myshape_plus { 3 dict begin /blue exch def /green exch def /red exch def gsave 0 0 moveto -15 0 rlineto -15 10 -15 90 -5 100 rcurveto 0 10 rlineto -5 0 rlineto 0 10 rlineto 25 0 rlineto 0 -10 rlineto -5 0 rlineto 0 -10 rlineto 15 -10 15 -90 5 -100 rcurveto gsave red green blue setrgbcolor fill grestore stroke grestore end % end dict begin } def 100 100 translate myshape 100 0 translate 1 0 0 myshape_plus -40 180 translate 0 1 18 { /iter exch def iter 4 mul rotate 30 30 translate iter 2 mod 0 eq { myshape } { 1 0.5 0.5 myshape_plus } ifelse } for /pi 3.1416 def % define variable showpage
كما هو موضح بالمثال أعلاه فأننا قمنا بأستخدام جملة ifelse
الشرطية التي تقوم بشيء في حالة تحقق الشرط وإلا تنتقل إلى جسد القوسان التاليان وهناك جملة شرطية آخرى ببوست سكربت وهي الأبسط if
فيها فقط قوسان وليس أربعة وأما لإيضاح الشرط فيجب أن يتكون الشرط من مقارنة منطقية بأستخدام شرط من الشروط مثل يساوي eq
, لا يساوي ne
, أكبر من gt
, أكبر من أو يساوي ge
, أصغر من lt
, أصغر من أو يساوي le
ومن الملاحط أستعمالي لدالة باقي القسمة mod
حتى أحقق تفاوت في الرسم عبر رسم ما باقي قسمته على أثنين يساوي صفر بلا لون وما لا يساوي صفر بلون.
رغم أنني لم أستخدام بعض رموز الأحتمال والمنطق لكن سأشير إليها إشارة سريعة: «و» المنطقية and
, «أو» or
, «أو الحصرية» xor
, صحيح true
, غير صحيح false
, ليس not
.
لتعريف المتغيرات ذات النطاق المحلي علينا إنشاء قاموس يضمها وذلك عبر تحدديد عددهم ووضعهم داخل جملتين n dict begin
وختمها بـ end
حيث n هو عدد المتغيرات.
المزيد من الوصفات
غلاف كتاب:
% the trick is to draw our object in the center point and then translate it because if we rotate % our object far from the center point the object would move of y and x axis's /ara_zahrafa { 10 dict begin /y exch def /x exch def /lwidth 10 def gsave lwidth setlinewidth x y translate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath gsave 0 1 0 setrgbcolor fill grestore stroke 45 rotate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath gsave 0 0 1 setrgbcolor fill grestore stroke %%%%%%%%%%%%%%%%%%%%%%%%%%%% second stage (inner area) -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath clip newpath 45 rotate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath gsave 1 0 0 setrgbcolor fill grestore stroke %%%%%%%%%%%%%%%%%%%% Making the inner borders looks nice -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath clip newpath 45 rotate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath stroke grestore } def 0.5 0.5 scale 0 1 5 { /iter0 exch def 0 1 4 { /iter exch def gsave iter 300 mul iter0 300 mul ara_zahrafa grestore } for } for 1 setgray 100 100 1000 1300 rectfill 10 setlinewidth 0 setgray 100 100 1000 1300 rectstroke /Times-Roman findfont 200 scalefont setfont newpath 200 1000 moveto (The Book) show /Times-Roman findfont 50 scalefont setfont newpath 340 900 moveto (On Explaining Something) show /Times-Roman findfont 50 scalefont setfont newpath 230 500 moveto (Eng. Mr. Sci. Gen. Author Ibn Author) show /Times-Roman findfont 50 scalefont setfont newpath 380 200 moveto (Happy Hacking Press) show showpage
قف:
0 0 900 900 rectfill % black background /stop_sign { 10 dict begin /y exch def /x exch def /lwidth 10 def gsave lwidth setlinewidth 1 setgray x y translate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath clip newpath 45 rotate -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath gsave 1 0 0 setrgbcolor fill grestore stroke %%%%%%%%%%%%%%%%%%%%%%% newpath lwidth setlinewidth -100 -100 moveto 200 0 rlineto 0 200 rlineto -200 0 rlineto closepath clip 45 rotate -100 lwidth 2 div add 1 sub -100 lwidth 2 div add 1 sub 200 lwidth sub 2 add 200 lwidth sub 2 add rectstroke -90 rotate /Times-Roman findfont 75 scalefont setfont newpath -90 -29 moveto (STOP) show stroke grestore end } def 0 1 4 { /iter0 exch def 0 1 4 { /iter exch def gsave 1 1 1 setrgbcolor iter 200 mul iter0 200 mul stop_sign grestore } for } for showpage
لوحة مفاتيح:
<< /PageSize [842 1191] >> setpagedevice % height width corner text fontsize /key { 9 dict begin /fontsize exch def /text exch def /corner exch def /width exch def /height exch def % gsave newpath width 2 div height 2 div corner 0 90 arc width neg 0 rlineto width 2 div neg height 2 div corner 90 -180 arc 0 height neg rlineto width 2 div neg height 2 div neg corner -180 -90 arc width 0 rlineto width 2 div height 2 div neg corner -90 0 arc % 0 height rlineto closepath stroke /Times-Roman findfont fontsize scalefont setfont newpath width 3 div neg 0 moveto text show end } def % height width corner text fontsize space /insert { 9 dict begin /space exch def /fontsize exch def /text exch def /corner exch def /width exch def /height exch def height width corner text fontsize key width corner 2 mul add space add 0 translate end } def 0.49 0.49 scale gsave % BEGIN 1 row 50 500 translate 50 50 10 (Esc) 25 90 insert 50 50 10 (F1) 25 5 insert 50 50 10 (F2) 25 5 insert 50 50 10 (F3) 25 5 insert 50 50 10 (F4) 25 50 insert 50 50 10 (F5) 25 5 insert 50 50 10 (F6) 25 5 insert 50 50 10 (F7) 25 5 insert 50 50 10 (F8) 25 50 insert 50 50 10 (F9) 25 5 insert 50 50 10 (F10) 25 5 insert 50 50 10 (F11) 25 5 insert 50 50 10 (F12) 25 20 insert 50 50 10 () 20 5 insert -105 20 moveto (Print) show -105 0 moveto (Scrn) show -105 -5 moveto (_____) show -105 -25 moveto (Sys Rq) show 50 50 10 () 25 5 insert -105 5 moveto (Scroll) show -105 -20 moveto (Lock) show 50 50 10 () 20 5 insert -100 10 moveto (Pause) show -100 0 moveto (_____) show -100 -20 moveto (Sys Rq) show grestore % END 1 row gsave % BEGIN 2 row 50 410 translate 50 50 10 (~) 25 5 insert 50 50 10 (1) 25 5 insert 50 50 10 (2) 25 5 insert 50 50 10 (3) 25 5 insert 50 50 10 (4) 25 5 insert 50 50 10 (5) 25 5 insert 50 50 10 (6) 25 5 insert 50 50 10 (7) 25 5 insert 50 50 10 (8) 25 5 insert 50 50 10 (9) 25 5 insert 50 50 10 (0) 25 5 insert 50 50 10 (-) 25 5 insert 50 50 10 (+) 25 55 insert 50 150 10 (<- Backspace) 25 0 insert -30 0 translate 50 50 10 (Insert) 20 5 insert 50 50 10 (Home) 20 5 insert 50 50 10 () 20 20 insert -100 10 moveto (Page) show -100 -20 moveto (Up) show 50 50 10 () 20 5 insert -100 10 moveto (Num) show -100 -20 moveto (Lock) show 50 50 10 (/) 20 5 insert 50 50 10 (*) 20 5 insert 50 50 10 (-) 20 5 insert grestore % END 2 row gsave % BEGIN 3 row 75 335 translate 50 100 10 (Tab) 25 0 insert -110 10 moveto (|<--) show -110 -20 moveto (-->|) show -20 0 translate 50 50 10 (q) 25 5 insert 50 50 10 (w) 25 5 insert 50 50 10 (e) 25 5 insert 50 50 10 (r) 25 5 insert 50 50 10 (t) 25 5 insert 50 50 10 (y) 25 5 insert 50 50 10 (u) 25 5 insert 50 50 10 (i) 25 5 insert 50 50 10 (o) 25 5 insert 50 50 10 (p) 25 5 insert 50 50 10 ({) 25 5 insert 50 50 10 (}) 25 30 insert 50 100 10 (|) 25 25 insert -30 0 translate 50 50 10 (Delete) 20 5 insert 50 50 10 (End) 20 5 insert 50 50 10 () 20 20 insert -100 10 moveto (Page) show -110 -20 moveto (Down) show 50 50 10 (7) 20 5 insert 50 50 10 (8) 20 5 insert 50 50 10 (9) 20 5 insert 0 -38 translate 127 50 10 (+) 20 5 insert grestore % END 3 row gsave % BEGIN 4 row 75 260 translate 10 0 translate 50 120 10 (Caps) 25 0 insert -180 -30 moveto (Lock) show -110 20 moveto 0 -40 rlineto stroke -30 0 translate 50 50 10 (a) 25 5 insert 50 50 10 (s) 25 5 insert 50 50 10 (d) 25 5 insert 50 50 10 (f) 25 5 insert 50 50 10 (g) 25 5 insert 50 50 10 (h) 25 5 insert 50 50 10 (j) 25 5 insert 50 50 10 (k) 25 5 insert 50 50 10 (l) 25 5 insert 50 50 10 (:) 25 5 insert 50 50 10 (") 25 58 insert 50 155 10 (<--| Enter) 25 207 insert 50 50 10 (4) 20 5 insert 50 50 10 (5) 20 5 insert 50 50 10 (6) 20 5 insert grestore % END 4 row gsave % BEGIN 5 row 75 185 translate 15 0 translate 20 0 translate 50 175 10 (/|\\ Shift) 25 0 insert -55 0 translate 50 50 10 (z) 25 5 insert 50 50 10 (x) 25 5 insert 50 50 10 (c) 25 5 insert 50 50 10 (v) 25 5 insert 50 50 10 (b) 25 5 insert 50 50 10 (n) 25 5 insert 50 50 10 (m) 25 5 insert 50 50 10 (<) 25 5 insert 50 50 10 (>) 25 5 insert 50 50 10 (?) 25 68 insert 50 175 10 (/|\\ Shift) 25 20 15 add insert 50 50 10 (/|\\) 25 92 insert 50 50 10 (1) 20 5 insert 50 50 10 (2) 20 5 insert 50 50 10 (3) 20 5 insert 0 -40 translate 127 50 10 (Enter) 20 5 insert grestore % END 5 row gsave % BEGIN 6 row 70 110 translate 50 90 10 (Ctrl) 25 40 insert -55 0 translate 50 60 10 (GNU) 25 0 insert 50 50 10 (Alt) 25 235 insert 50 510 10 ( Space) 25 0 insert -225 0 translate 50 50 10 (Alt) 25 5 insert 50 60 10 (GNU) 25 0 insert 50 50 10 (_=-) 25 25 insert 50 90 10 (Ctrl) 25 3 insert 50 50 10 (<) 25 5 insert 50 50 10 (\\|/) 25 5 insert 50 50 10 (>) 25 54 insert 50 125 10 (0) 20 0 insert -32 0 translate 50 50 10 (.) 20 5 insert grestore % END 6 row showpage
زهور:
%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 595 842 %%Title: t.ps %%Creator: Hacker %%CreationDate: Wed Aug 26 00:19:36 2020 %%EndComments 64 dict begin % xpos ypos scale /tri-cir-symbol { 64 dict begin /B exch def /G exch def /R exch def /xyscale exch def /ypos exch def /xpos exch def gsave xpos ypos translate 10 setlinewidth xyscale xyscale scale 0 45 360 { /iter exch def iter rotate 200 0 83 -90 90 arc 0 0 lineto closepath gsave R G B setrgbcolor fill grestore stroke } for grestore end } def gsave 0 0.5 0.5 setrgbcolor 0 0 1000 1000 rectfill grestore 0 1 6 { /iter0 exch def 0 1 6 { /iter1 exch def gsave 120 iter1 mul 120 iter0 mul 0.2 1 1 0 tri-cir-symbol grestore } for } for 0 1 6 { /iter0 exch def 0 1 6 { /iter1 exch def gsave 120 iter1 mul 120 iter0 mul 0.15 0 1 0 tri-cir-symbol grestore } for } for 0 1 6 { /iter0 exch def 0 1 6 { /iter1 exch def gsave 120 iter1 mul 120 iter0 mul 0.09 1 0 0 tri-cir-symbol grestore } for } for end showpage %%EOF
الين واليان:
300 500 moveto 500 300 100 300 300 100 curveto 300 300 200 -90 90 arc 6 setlinewidth gsave fill grestore stroke 300 300 200 90 -90 arc stroke 300 200 20 0 360 arc 1 setgray fill 300 400 20 0 360 arc 0 setgray fill showpage
صفحات متعددة بأحجام وأستدارة مختلفة:
%!PS-Adobe-3.0 %%Title: landscape PDF example %%Pages: 3 %%EndComments %%BeginProlog %%EndProlog %%BeginSetup % Document information [/CreationDate (D:20040224) /Creator (Hand crafted by Russell Lang) /Title (landpdf.ps) % note that GS can get title from DSC %%Title /Subject (Example of landscape and portrait pages) /Keywords (landscape portrait example Ghostscript DOCINFO) /Author (Ghostgum Software Pty Ltd) /DOCINFO pdfmark %%EndSetup %%Page: 1 1 % Set the page size to A4 << /PageSize [595 842] >> setpagedevice /Helvetica findfont 100 scalefont setfont 100 200 moveto (1 portrait) show showpage %%Page: 2 2 %%PageOrientation: landscape % Set the page size to A3 << /PageSize [842 1191] /Orientation 3 >> setpagedevice 90 rotate 0 -842 translate /Helvetica findfont 100 scalefont setfont 100 200 moveto (2 landscape) show showpage %%Page: 3 3 % Set the page size to A4 << /PageSize [595 842] >> setpagedevice /Helvetica findfont 100 scalefont setfont 100 200 moveto (3 portrait) show showpage %%Trailer %%EOF
تهكيرات عجيبة
أشياء غير أعتيادية في بوست سكريبت لم يصمم بوست سكريبت لها:
- لعبة الحياة كون وي (هذه ليست لعبة أصلاً هذه خوارزمية أبتكرها عالم الرياضيات جون كون وي ليصف تطور العناصر بشكل رياضي) مكتوبة ببوست سكريبت.
- خادم (server) مكتوب بلغة بوست سكربت لم تتح لي فرصة تجربته لأنه يعتمد على برنامج inetd الخاص بالشبكات والذي تم أستبداله ببرنامج xinetd ولست خبيراً فيهما.
ماذا بعد
في هذه المقالة طرحنا الأساسيات فالخطوة التالية تكون بقراءة الدليل الرسمي1 الصادر بسنة 1985 وأخر نسخة بسنة 1999 وهنا إشارة لقدم هذه اللغة التي طورها مؤسسوا شركة أدوبي وقد أستعملت وما زالت تستعمل في الطباعة بشكل كبير.
ومن ناحية أخرى يمكنك الإطلاع على دليل ghostscript الرسمي للتعرف على خيارات هذا البرنامج وكما أنصح بالإطلاع على شرح Paul Bourke الممتاز لبوست سكريبت.
يمكنكم الإطلاع على هذا الرابط المحتوي على بعض الزخارف الهندسية والإسلامية المرسومة بواسطة بوست سكريبت وهذا الرابط الذي يحتوي على فركتولات مرسومة ببوست سكريبت وإيضاً هذا الرابط وكتاب وصفات بوست سكريبت.
وبما أننا بعد هذه المقالة تعلمنا نموذج بوست سكريبت (PostScript drawing model) فبأستطاعتنا تعلم مكتبة Cairo (القاهرة) لأستعمال لصنع القطع الخاصة (Custom widgets) في GTK3 أو أستخدامها لتطوير برنامج يصدر مستندات بشكل تلقائي أو محرر مستندات وذلك لأن مكتبة القاهرة البرمجية إذا ما أستعملت مع مكتبة بانغو (Pango) يمكنها دعم اللغة العربية وكل لغات العالم وتستطيع دعم العديد من المميزات للخطوط وهكذا تتخطى مشكلة بوست سكريبت مع الخطوط.
ونختم هذه المقالة بالقول أن هناك ما تزال بعض خوارزميات الضغط في بوست سكريبت خاضعة لبراءات الأختراع فوجب التنبيه.