написание арабского текста в opengl - PullRequest
4 голосов
/ 17 февраля 2009

Я хочу написать арабский текст в моей программе opengl, используя freetype 2, как я могу это сделать, любой может отправить мне исходный код или показать мне способ или даже любую модификацию на своем уроке 43, чтобы написать арабский язык в opengl, который объясняет использование freetype для отображения арабского текста


Я видел урок 13 и урок 43 раньше, но проблема в том, что когда я рендерил его, он показывает мне только прямоугольные границы без какой-либо арабской буквы, и я использовал glUseOutline, и он показывает мне буквы слева направо и без его подключения. вместе, проблема в арабском письме состоит в том, что некоторые буквы должны учитывать его положение, например, буква (ب) когда эта буква находится в начале слова (строки), она имеет собственную форму, а также в середине и в конце, поэтому, если для нее специально написан исходный код, это будет очень хорошим примером слова, как показано ниже : بيع буква ب находится в начале يبيع буква ب находится посередине ريب буква ب находится в конце

Ответы [ 5 ]

3 голосов
/ 17 февраля 2009

Ознакомьтесь с уроком NeHe 13 о рендеринге растровых шрифтов с OpenGL . Вы, вероятно, хотите использовать широкие символы вместо 8-битных, если вы хотите представлять арабский текст. Там есть пара примеров, некоторые из них используют Linux и FreeType. У Freetype не должно быть проблем с отображением символов Юникода. Это FreeType учебное пособие может помочь.

2 голосов
/ 26 июня 2013

Это похоже на то, что должно работать: https://github.com/Accorpa/Arabic-Converter-From-and-To-Arabic-Presentation-Forms-B/blob/master/ArabicConverter.m

Арабские глифы преобразуются в соответствующие им формы представления B и должны корректно отображаться, то есть правильно соединяться. Судя по всему, он использует псевдокод jheriko сверху.

РЕДАКТИРОВАТЬ (26 сентября 2016 г.): я знаю, что это было давно, я опубликовал оригинальный ответ. Хотя это не так, тем временем я использовал следующий код для преобразования арабских букв. Это очень простое решение, чтобы получить формы представления для арабских букв. https://github.com/eloraiby/arabtype/blob/master/arabtype.c

.

1 голос
/ 17 ноября 2009

Взгляните на نصوص عربية في أوبن جي إل (арабский), это обсуждение на арабском форуме, которое охватывает все проблемы, с которыми вы столкнетесь при рендеринге арабского текста в OpenGL, даже самые сложные .

Я не знаю, говорите ли вы по-арабски или нет, но на второй странице вы найдете пример кода, который рассказывает, как писать арабский текст с использованием GDI +:

// مثال عن كود برمجي يقوم برسم النصوص على سطوح دايركت ثري دي
// لغة البرمجة هي دوت نيت مع
// C++/CLI
// ونستخدم مكتبة
// GDI+
// لكتابة النصوص
// تقديم: وسام البهنسي
// الشبكة العربية لمطوري الألعاب
// http://www.agdn-online.com
// رداً على الموضوع:
// http://www.agdn-online.com/communities.aspx?view=posts&threadid=544

// يقوم هذا الكلاس بإدارة الموارد اللازمة لرسم النصوص العربية
private ref class ArabicTextRenderer
{
public:
 ArabicTextRenderer() :
   m_NativeData(0)
 {
  // أنشئ صورة بأبعاد تتسع لأكبر جملة نصية تتوقع كتابتها بضربة واحدة
  // لاحظ أن هيئة البكسلات مهمة جداً، ويجب أن توافق هيئة السطح في محرك الرسم
  // وذلك لتفادي أي عمليات تحويل بطيئة
  m_Bitmap = gcnew Bitmap(256, 128, PixelFormat::Format32bppRgb); // كل بكسل 32 بت. لا يهمنا قناة ألفا
  m_BitmapData = gcnew BitmapData();
  m_Graphics = Graphics::FromImage(m_Bitmap);

  // حدد خواص الكتابة. تنسيق يمين-يسار
  m_Format = gcnew StringFormat();
  m_Format->FormatFlags = StringFormatFlags::NoClip | StringFormatFlags::DirectionRightToLeft;
  m_Format->Alignment = StringAlignment::Near;
  m_Format->HotkeyPrefix = HotkeyPrefix::None;
  m_Format->LineAlignment = StringAlignment::Near;
  m_Format->Trimming = StringTrimming::None;

  // معلومات عن كيفية حفظ الصورة في الذاكرة. كي نستطيع قراءتها دون تحويلات مكلفة
  m_Stride = (m_Bitmap->Width * Bitmap::GetPixelFormatSize(m_Bitmap->PixelFormat)) / 8; // عرض الصورة بالبايت
  int iBytesCount = m_Bitmap->Height * m_Stride; // حجم الصورة ككل بالبايت
  m_NativeData = new char[iBytesCount]; // المصفوفة الوسيطة التي ستستلم القيم اللونية للصورة

  // تجهيز معلومات الصورة لإجراء القفل
  m_BitmapData->Width = m_Bitmap->Width;
  m_BitmapData->Height = m_Bitmap->Height;
  m_BitmapData->PixelFormat = m_Bitmap->PixelFormat;
  m_BitmapData->Stride = m_Stride;
  m_BitmapData->Scan0 = (IntPtr)m_NativeData;
 }

 ~ArabicTextRenderer()
 {
  // حرر الذاكرة التي حجزناها بأنفسنا
  delete [] m_NativeData;
 }

 // إجراءات لتسهيل الوصول إلى أعضاء الكلاس
 property Bitmap^ TextBitmap { Bitmap^ get(void) { return m_Bitmap; } }
 property BitmapData^ TextBitmapData { BitmapData^ get(void) { return m_BitmapData; } }
 property Graphics^ TextGraphics { Graphics^ get(void) { return m_Graphics; } }
 property StringFormat^ TextFormat { StringFormat^ get(void) { return m_Format; } }
 property int Stride { int get(void) { return m_Stride; } }
 property void* NativeData { void* get(void) { return m_NativeData; } }

private:
 Graphics ^m_Graphics; // جهاز الرسم بجي دي آي بلس
 Bitmap ^m_Bitmap; // الصورة التي سيتم الرسم عليها
 BitmapData ^m_BitmapData; // معلومات القفل والتعبئة
 StringFormat ^m_Format; // خواص الكتابة
 int m_Stride; // عرض الصورة بالبايت. انتبه، قد يكون أكبر من عدد البكسلات مضروباً بحجم كل منها
 void *m_NativeData; // مؤشر إلى القيم اللونية للصورة
};


// إجراء الكتابة على صورة وتحويلها إلى بايتات يمكن إرسالها إلى أي محرك رسم
// البارامتر الأول هو النص المرغوب كتابته
// البارامتر الثاني هو الخط المرغوب للكتابة
// البارامتر الثالث هو كلاس الكتابة بالعربية والذي يجب أن يكون قد تم إنشاؤه من قبل
// البارامتر الأخير هو سطح دايركت ثري الذي ترغب بالرسم عليه
void SetText(String ^text, Font ^font, ArabicTextRenderer^ renderer, IDirect3DSurface9* D3DSurface)
{
 Bitmap ^bmp = renderer->TextBitmap;
 Graphics ^gfx = renderer->TextGraphics;

 // أولاً نقوم بمسح محتويات الصورة كي نتخلص من أي بقايا من المرة الماضية
 gfx->Clear(System::Drawing::Color::Transparent);

 // يجب علينا أن نقيس النص كي نستطيع توضيعه بشكل صحيح في الصورة
 SizeF sizef = gfx->MeasureString(text, font, PointF(0,0), renderer->TextFormat);
 short width = (short)sizef.Width;
 short height = (short)sizef.Height+2; // ضع هامشاً بمقدار بكسل واحد كارتفاع
 float yo = 1; // الإزاحة من أعلى الصورة

 // ارسم النص بدءاً من النقطة المحددة
 // لاحظ أن نقطة الكتابة هي الزاوية العليا اليمنى للنص لأننا نكتب بالعربية،
 // وبالتالي نحن بحاجة إلى وضع هذه النقطة على أقصى يمين الصورة
 gfx->DrawString(text, font, Brushes::White, width , yo, renderer->TextFormat);

 // يمكنك رسم إطار حول النص لو أردت التحقق من صحة الحسابات
 //gfx->DrawRectangle(Pens::White, 0, 0, width-1, height-1);

 // المستطيل الذي يحدد المنطقة التي نود قفلها من الصورة. عملياً كل الصورة
 Rectangle rc(0,0,bmp->Width,bmp->Height);

 // نقل القيم اللونية من الصورة إلى المؤشر الخاص بنا
 // هذه العملية تتم بمجرد قفل بتات الصورة، وذلك وفقاً للبارامترات التي نمررها
 // لإجراء القفل. هذه العملية سريعة نسبياً لأننا نسحب المعلومات بدون أي تحويل.
 bmp->LockBits(rc,ImageLockMode::ReadOnly|ImageLockMode::UserInputBuffer,
               bmp->PixelFormat,renderer->TextBitmapData);
 bmp->UnlockBits(renderer->TextBitmapData);

 // الآن لدينا كل ما يلزم لوضع البكسلات في محرك الرسم
 // الإجراء التالي يضع البكسلات في سطح دايركت ثري دي كمثال
 CopyImageToD3DSurface(D3DSurface, renderer->NativeData, renderer->Stride, width, height);

 //bmp->Save(L"C:\\صورة.png"); // احفظ الصورة للتحقق
}


// إجراء تعبئة سطح دايركت ثري دي بقيم لونية من مصفوفة ما. أي محرك رسم يجب أن يقدم إجراءً مماثلاً
// البارامتر الأول هو السطح المرغوب تعبئته
// البارامتر الثاني هو مصفوفة القيم اللونية التي تريد نسخها على السطح
// البارامتر الثالث هو عرض مصفوفة القيم اللونية بالبايت، وليس بالبكسل
// البارامتر الرابع والخامس هما أبعاد مصفوفة القيم اللونية بالبكسل. العرض والارتفاع على الترتيب
void CopyImageToD3DSurface(IDirect3DSurface9* D3DSurface, void* sourcePixels,
                           int stride, int width, int height)
{
 // هناك عدة افتراضات هنا لتبسيط الكود للمتعلم:
 // حجم السطح أكبر من أو يساوي أبعاد مصفوفة القيم اللونية
 // هيئة السطح هي ذاتها هيئة مصفوفة القيم اللونية. بمعنى آخر، لو كانت القيمة
 // اللونية مؤلفة من 4 بايتات، كل منها قناة لونية أحمر، أخضر، أزرق، ألفا
 // فإن سطح دايركت ثري دي يجب أن يكون من الهيئة:
 // D3DFMT_A8R8G8B8 أو D3DFMT_X8R8G8B8

 // انسخ القيم اللونية من كامل المصفوفة
 RECT srcRect = {0, 0, height, width};

 // انسخ القيم اللونية إلى الزاوية العليا اليسارية من السطح
 RECT destRect = {0, 0, height, width};

 // إجراء تعبئة السطح من مصفوفة قيم لونية مقدم من مكتبة دايركت ثري دي الإضافية
 D3DXLoadSurfaceFromMemory(
  D3DSurface, // السطح الذي يتم تعبئته
  NULL, // مصفوفة بجدول الألوان. لا نستخدم هذه الميزة
  &destRect, // المستطيل الذي سيتم تعبئته بالقيم اللونية في الصورة
  sourcePixels, // مصفوفة القيم اللونية التي سيتم النسخ منها
  D3DFMT_X8R8G8B8, // هيئة القيم اللونية. 32 بت وقناة ألفا غير مهمة
  stride, // عرض مصفوفة القيم اللونية بالبايت
  NULL, // مصفوفة بجدول الألوان في مصفوفة القيم اللونية. لا نستخدم هذه الميزة
  &srcRect, // المستطيل الذي يعبر عن مكان النسخ من مصفوفة القيم اللونية
  D3DX_FILTER_NONE, // طريقة الترشيح في حال عدم تطابق الأبعاد. لا نريد أي ترشيح
  0); // اللون المفتاحي. سيتم استبدال جميع القيم اللونية المطابقة لهذا اللون باللون الشفاف
}

Другой участник изменил код для работы с OpenGL, и результат был успешным: alt text
(источник: agdn-online.com )

Вы можете скачать код здесь .

0 голосов
/ 08 апреля 2013

Как включить поддержку арабского в этом коде?

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs)
    Call SaveSetting(My.Application.Info.ProductName, "Base", "LastText", Me.RichTextBox1.Rtf)
End Sub


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Me.RichTextBox1.Rtf = GetSetting(My.Application.Info.ProductName, "Base", "LastText", "")
    If Me.RichTextBox1.TextLength = 0 Then Me.RichTextBox1.LoadFile("info.rtf")

End Sub


Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs)
    Me.Timer1.Enabled = True
End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    Me.Timer1.Enabled = False


    Dim b As New Bitmap(Me.PictureBox1.Width, Me.PictureBox1.Height)
    Me.PictureBox1.Image = b
    Me.PictureBox1.Image = Image.FromFile(CurDir() & "\allpic\OperaDe1AFace.jpg")
    Rtb.RichTextBoxToBitmap(Me.RichTextBox1, Me.PictureBox1.Image)


End Sub

Private Sub RichTextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RichTextBox1.TextChanged
    Me.Timer1.Enabled = True
End Sub

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

End Sub

Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

End Sub

Private Sub PictureBox2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

End Sub

Private Sub PictureBox1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs)

End Sub

Private Sub NewToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NewToolStripMenuItem.Click

End Sub





Private Sub PictureBox1_Click_2(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click

End Sub

Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    StartPoint = PictureBox1.PointToScreen(New Point(e.X, e.Y))
    IsDragging = True
End Sub

Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    If IsDragging Then
        Dim EndPoint As Point = PictureBox1.PointToScreen(New Point(e.X, e.Y))
        PictureBox1.Left += (EndPoint.X - StartPoint.X)
        PictureBox1.Top += (EndPoint.Y - StartPoint.Y)
        StartPoint = EndPoint
    End If
End Sub

Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
    IsDragging = False
End Sub

Конечный класс

0 голосов
/ 01 августа 2009

Возможно, вы захотите использовать промежуточное представление, чтобы все четыре формы символов при вводе преобразовывались в одну форму. Затем, если вы создаете массив классов / структур, содержащих ссылки на каждую из четырех форм правильных кодов символов, вы можете изменить строку, прочитанную средством визуализации текста, чтобы она выбирала правильную с некоторой логикой, подобной этому psuedocode:

for each character in the input string

  find its entry in the array containing the character codes for the four forms

  if this is the first character
    if the next character is a space then 
      use the isolated form in the output string
    else
      use the initial form in the output string
  else
    if the preceeding character is a space and the next character is a space then
      use the isolated form in the output string
    else if the preceeding character is a space then use
      the initial form in the output string
    else if the next character is a space then
      use the terminal form in the output string
    else
      use the medial form in the output string
...