سؤال

يقوم برنامجي بإنشاء مستندات PDF بسيطة نسبيًا عند الطلب، ولكن أواجه مشكلة مع أحرف Unicode، مثل كانجي أو رموز الرياضيات الفردية.لكتابة سلسلة عادية في ملف PDF، ضعها بين قوسين:

(something)

هناك أيضًا خيار الهروب من الحرف ذي الرموز الثمانية:

(\527)

ولكن هذا يصل إلى 512 حرفًا فقط.كيف يمكنك تشفير أو الهروب من الشخصيات الأعلى؟لقد رأيت إشارات إلى تدفقات البايت والسلاسل المشفرة السداسية، ولكن لا يبدو أن أيًا من المراجع التي قرأتها على استعداد لإخباري بكيفية القيام بذلك بالفعل.


يحرر: وبدلاً من ذلك، وجهني إلى مكتبة Java PDF جيدة يمكنها القيام بهذه المهمة نيابةً عني.الإصدار الذي أستخدمه حاليًا هو إصدار gnujpdf (الذي قمت بإصلاح العديد من الأخطاء فيه، حيث يبدو أن المؤلف الأصلي قد رحل بدون إذن)، والذي يسمح لك بالبرمجة مقابل واجهة رسومات AWT، ومن الناحية المثالية يجب أن يكون أي بديل مناسبًا نفس الشيء.

يبدو أن البدائل إما HTML -> PDF، أو نموذج برمجي يعتمد على الفقرات والمربعات التي تشبه إلى حد كبير HTML.iText هو مثال على هذا الأخير.وهذا يعني إعادة كتابة الكود الحالي الخاص بي، ولست مقتنعًا بأنهم سيعطونني نفس المرونة في التخطيط.


تحرير 2: لم أكن أدرك ذلك من قبل، ولكن مكتبة iText تحتوي على واجهة برمجة تطبيقات Graphics2D ويبدو أنها تتعامل مع Unicode بشكل مثالي، لذلك هذا ما سأستخدمه.على الرغم من أنها ليست إجابة على السؤال كما هو مطروح، إلا أنها تحل المشكلة بالنسبة لي.


تحرير 3: iText يعمل بشكل جيد بالنسبة لي.أعتقد أن الدرس المستفاد هو، عندما تواجه شيئًا يبدو صعبًا بلا جدوى، ابحث عن شخص يعرف عنه أكثر منك.

هل كانت مفيدة؟

المحلول

الجواب البسيط هو أنه لا توجد إجابة بسيطة.إذا ألقيت نظرة على مواصفات PDF، سترى فصلاً كاملاً - وفصلًا طويلًا - مخصصًا لآليات عرض النص.لقد نفذت كل دعم PDF لشركتي، وكان التعامل مع النص هو الجزء الأكثر تعقيدًا في التمرين.الحل الذي اكتشفته - استخدام مكتبة تابعة لجهة خارجية لإنجاز العمل نيابةً عنك - هو حقًا الخيار الأفضل، إلا إذا كانت لديك متطلبات محددة جدًا لأغراض خاصة لملفات PDF الخاصة بك.

نصائح أخرى

في مرجع PDF في الفصل 3، هذا ما يقولونه عن Unicode:

يتم ترميز سلاسل النص في إما pdfdocencoding أو ترميز أحرف Unicode.PDFDOCENCODING هي مجموعة من ترميز ISO LATIN 1 وتم توثيقها في الملحق D.يوصف Unicode في معيار Unicode بواسطة اتحاد Unicode (انظر ببليوغرافيا).بالنسبة للسلاسل النصية المشفرة في Unicode ، يجب أن يكون أول بايتان 254 متبوعًا بـ 255.يمثل هذان البايتان علامة ترتيب بايت Unicode ، U+FEFF ، مما يشير إلى أن السلسلة مشفرة في مخطط ترميز UTF-16BE (الكبير-إنديان) المحدد في معيار UNICODE.(تمنع هذه الآلية بدء سلسلة باستخدام pdfdocencoding مع حرفين شائكة ydieresis ، والتي من غير المرجح أن تكون بداية ذات معنى لكلمة أو عبارة).

إجابة ألغومان هي خطأ في أشياء كثيرة.أنت يستطيع إنشاء مستندات PDF تحتوي على Unicode، وهو ليس علمًا صواريخيًا، على الرغم من أنه يحتاج إلى بعض العمل.نعم إنه على حق، لاستخدام أكثر من 255 حرفًا في خط واحد، عليك إنشاء كائن pdf بخط مركب (CIDFont).ثم تذكر فقط خط TrueType الفعلي الذي تريد استخدامه كمدخل DescendatFont لـ CIDFont.الحيلة هي أنه بعد ذلك عليك أن تستخدم مؤشرات الصورة الرمزية الخط بدلاً من رموز الأحرف.للحصول على خريطة المؤشرات هذه عليك التحليل cmap قسم من الخط - احصل على محتويات الخط باستخدام GetFontData الوظيفة والتعامل مع مواصفات TTF.وهذا كل شيء!لقد فعلت ذلك للتو والآن لدي ملف pdf يونيكود!

نموذج التعليمات البرمجية للتحليل cmap القسم هنا: https://support.microsoft.com/en-us/kb/241020

ونعم، لا تنس إدخال /ToUnicode كما أشار @user2373071 وإلا فلن يتمكن المستخدم من البحث في ملف PDF الخاص بك أو نسخ النص منه.

كما أشار dredkin، يجب عليك استخدام فهارس الحروف الرسومية بدلاً من قيمة أحرف Unicode في تدفق محتوى الصفحة.يعد هذا كافيًا لعرض نص Unicode في ملف PDF، لكن نص Unicode لن يكون قابلاً للبحث.لجعل النص قابلاً للبحث أو لعمل نسخ/لصق عليه، ستحتاج أيضًا إلى تضمين دفق /ToUnicode.يجب أن يقوم هذا الدفق بترجمة كل حرف رسومي في المستند إلى حرف Unicode الفعلي.

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

تحقق من PDFBox أو iText.

http://www.adobe.com/devnet/pdf/pdf_reference.html

لقد عملت عدة أيام حول هذا الموضوع الآن وما تعلمته هو أن Unicode (جيد) مستحيل في PDF.استخدام أحرف ثنائية البايت بالطريقة الموضحة للقاعدة لا يعمل إلا مع خطوط CID.

على ما يبدو، خطوط CID هي عبارة عن بنية داخلية بتنسيق pdf وهي ليست في الحقيقة خطوطًا بهذا المعنى - فهي تبدو أشبه بالإجراءات الفرعية للرسومات، والتي يمكن استدعاؤها عن طريق معالجتها (بعناوين 16 بت).

لذلك لاستخدام Unicode في قوات الدفاع الشعبي مباشرة

  1. سيتعين عليك تحويل الخطوط العادية إلى خطوط CID، وهو أمر ربما يكون صعبًا للغاية - سيتعين عليك إنشاء إجراءات الرسومات من الخط الأصلي (؟)، واستخراج مقاييس الأحرف وما إلى ذلك.
  2. لا يمكنك استخدام خطوط CID مثل الخطوط العادية - لا يمكنك تحميلها أو تغيير حجمها بالطريقة التي تقوم بها بتحميل الخطوط العادية وقياسها
  3. كما أن الأحرف ذات 2 بايت لا تغطي مساحة Unicode الكاملة

IMHO، هذه النقاط تجعل استخدام Unicode غير ممكن على الإطلاق مباشرة.



ما أفعله الآن بدلاً من ذلك هو استخدام الشخصيات بشكل غير مباشر بالطريقة الآتية:لكل خط، أقوم بإنشاء صفحة رموز (وجدول بحث لعمليات البحث السريعة) - في لغة c++، سيكون هذا شيئًا من هذا القبيل

std::map<std::string, std::vector<wchar_t> > Codepage;
std::map<std::string, std::map<wchar_t, int> > LookupTable;

بعد ذلك، عندما أرغب في وضع بعض سلسلة Unicode على الصفحة، أقوم بتكرار أحرفها، والبحث عنها في جدول البحث، وإذا كانت جديدة، أقوم بإضافتها إلى صفحة التعليمات البرمجية مثل هذا:

for(std::wstring::const_iterator i = str.begin(); i != str.end(); i++)
{                
    if(LookupTable[fontname].find(*i) == LookupTable[fontname].end())
    {
        LookupTable[fontname][*i] = Codepage[fontname].size();
        Codepage[fontname].push_back(*i);
    }
}

بعد ذلك، أقوم بإنشاء سلسلة جديدة، حيث يتم استبدال الأحرف من السلسلة الأصلية بمواضعها في صفحة التعليمات البرمجية مثل هذا:

static std::string hex = "0123456789ABCDEF";
std::string result = "<";
for(std::wstring::const_iterator i = str.begin(); i != str.end(); i++)
{                
    int id = LookupTable[fontname][*i] + 1;
    result += hex[(id & 0x00F0) >> 4];
    result += hex[(id & 0x000F)];
}
result += ">";

على سبيل المثال ، "H € LLO World!" قد تصبح <01020303040506040703080905> والآن يمكنك فقط وضع هذه السلسلة في PDF وطباعتها ، باستخدام مشغل TJ كالمعتاد ...

ولكن لديك الآن مشكلة:لا يعرف ملف pdf أنك تقصد "H" بالرقم 01.لحل هذه المشكلة، عليك أيضًا تضمين صفحة الرموز في ملف pdf.ويتم ذلك عن طريق إضافة /التشفير إلى كائن الخط وتعيينه اختلافات

من أجل "H € LLO World!" على سبيل المثال ، سيعمل هذا الخطوط:

5 0 obj 
<<
    /F1
    <<
        /Type /Font
        /Subtype /Type1
        /BaseFont /Times-Roman
        /Encoding
        <<
          /Type /Encoding
          /Differences [ 1 /H /Euro /l /o /space /W /r /d /exclam ]
        >>
    >> 
>>
endobj 

أقوم بإنشائه باستخدام هذا الرمز:

ObjectOffsets.push_back(stream->tellp()); // xrefs entry
(*stream) << ObjectCounter++ << " 0 obj \n<<\n";
int fontid = 1;
for(std::list<std::string>::iterator i = Fonts.begin(); i != Fonts.end(); i++)
{
    (*stream) << "  /F" << fontid++ << " << /Type /Font /Subtype /Type1 /BaseFont /" << *i;

    (*stream) << " /Encoding << /Type /Encoding /Differences [ 1 \n";
    for(std::vector<wchar_t>::iterator j = Codepage[*i].begin(); j != Codepage[*i].end(); j++)
        (*stream) << "    /" << GlyphName(*j) << "\n";
    (*stream) << "  ] >>";

    (*stream) << " >> \n";
}
(*stream) << ">>\n";
(*stream) << "endobj \n\n";

لاحظ أنني أستخدم سجل الخطوط العام - أستخدم نفس أسماء الخطوط /F1، /F2،...في جميع أنحاء وثيقة PDF بأكملها.تتم الإشارة إلى نفس كائن تسجيل الخط في ملف /موارد دخول جميع الصفحات.إذا قمت بذلك بشكل مختلف (على سبيل المثال.تستخدم تسجيل خط واحد لكل صفحة) - قد تضطر إلى تكييف الكود مع موقفك ...

إذًا كيف يمكنك العثور على أسماء الحروف الرسومية (/Euro لـ "€"، /exclam لـ "!" وما إلى ذلك)؟في الكود أعلاه، يتم ذلك ببساطة عن طريق استدعاء "GlyphName(*j)".لقد قمت بإنشاء هذه الطريقة باستخدام BASH-Script من القائمة الموجودة في

http://www.jdawiseman.com/papers/trivia/character-entities.html

ويبدو مثل هذا

const std::string GlyphName(wchar_t UnicodeCodepoint)
{
    switch(UnicodeCodepoint)
    {
        case 0x00A0: return "nonbreakingspace";
        case 0x00A1: return "exclamdown";
        case 0x00A2: return "cent";
        ...
    }
}

أ مشكلة رئيسية لقد تركت مفتوحة هو أن هذا يعمل فقط طالما أنك تستخدم 254 حرفًا مختلفًا على الأكثر من نفس الخطلاستخدام أكثر من 254 حرفًا مختلفًا، يجب عليك إنشاء صفحات رموز متعددة لنفس الخط.

داخل ملف pdf، يتم تمثيل صفحات الرموز المختلفة بخطوط مختلفة، لذا للتبديل بين صفحات الرموز، سيتعين عليك تبديل الخطوط، الأمر الذي قد يؤدي نظريًا إلى تضخيم ملف pdf الخاص بك قليلاً، لكنني شخصيًا، أستطيع التعايش مع ذلك...

أنا لست خبيرًا في ملفات PDF، و(كما قال Ferruccio) يجب أن تخبرك مواصفات PDF في Adobe بكل شيء، ولكن ظهرت فكرة في ذهني:

هل أنت متأكد من أنك تستخدم خطًا يدعم كافة الأحرف التي تحتاجها؟

في تطبيقنا، نقوم بإنشاء ملف PDF من صفحات HTML (باستخدام مكتبة تابعة لجهة خارجية)، وقد واجهنا هذه المشكلة مع الأحرف السيريلية...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top