Tôi đã làm việc vài ngày về chủ đề này ngay bây giờ và những gì tôi đã học được rằng unicode là (tốt như) không thể trong pdf. Sử dụng các ký tự 2 byte theo cách mà mô tả thứ chín chỉ hoạt động với CID-Phông chữ.
dường như, CID-phông chữ là một cấu trúc nội bộ pdf và chúng không thực sự là phông chữ theo nghĩa đó - chúng dường như giống như đồ họa con hơn, có thể được gọi bằng cách giải quyết chúng (với địa chỉ 16 bit).
Vì vậy, để sử dụng unicode trong pdf trực tiếp
- bạn sẽ phải chuyển đổi phông chữ bình thường để CID-Fonts, mà có lẽ là vô cùng khó khăn - bạn sẽ phải tạo ra thói quen đồ họa từ font gốc (?), trích xuất các chỉ số nhân vật, v.v.
- bạn không thể sử dụng phông chữ CID như phông chữ thông thường - bạn không thể tải hoặc chia tỷ lệ phông chữ theo cách bạn tải và chia tỷ lệ phông chữ bình thường
- không gian Unicode đầy đủ
IMHO, những điểm này làm cho nó hoàn toàn không khả thi khi sử dụng unicode trực tiếp.
Những gì tôi đang làm thay vì hiện đang sử dụng các nhân vật gián tiếp theo cách sau: Đối với mỗi font chữ, tôi tạo ra một bảng mã (và một tra cứu-bảng để tra cứu nhanh) - trong C++ đây sẽ là một cái gì đó giống như
std::map<std::string, std::vector<wchar_t> > Codepage;
std::map<std::string, std::map<wchar_t, int> > LookupTable;
sau đó, bất cứ khi nào tôi muốn đặt một số unicode dây trên một trang, tôi lặp nhân vật của mình, nhìn chúng trong việc tra cứu-bàn và - nếu họ là người mới, tôi thêm chúng đến trang mã như sau:
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);
}
}
sau đó, tôi tạo ra một chuỗi mới, nơi mà các ký tự từ chuỗi ban đầu được thay thế bằng vị trí của họ trong bảng mã như thế này: "H € llo World"
static std::string hex = "ABCDEF";
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 += ">";
ví dụ, có thể trở thành < 01020303040506040703080905> và bây giờ bạn có thể chỉ cần đặt chuỗi đó vào pdf và in nó, sử dụng toán tử Tj như bình thường ...
nhưng bây giờ bạn có vấn đề: pdf không biết rằng bạn có nghĩa là "H" vào ngày 01. Để giải quyết vấn đề này, bạn cũng phải bao gồm bảng mã trong tệp pdf. Này được thực hiện bằng cách thêm một /Encoding đến đối tượng Font và thiết khác biệt
của nó Đối với "H € llo World!" Ví dụ, đây Font-Object sẽ làm việc:
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
tôi tạo ra nó với mã này:
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";
Chú ý rằng tôi sử dụng một toàn cầu font-đăng ký - Tôi sử dụng các tên phông chữ tương tự/F1,/F2, ... trong toàn bộ tài liệu pdf. Cùng một đối tượng đăng ký phông chữ được tham chiếu trong mục /Resources Nhập tất cả các trang. Nếu bạn thực hiện điều này một cách khác nhau (ví dụ: bạn sử dụng một phông chữ đăng ký trên mỗi trang) - bạn có thể phải điều chỉnh mã cho tình huống của bạn ...
Vậy làm thế nào để bạn tìm thấy tên của hình tượng (/ Euro cho " € ",/exclam cho"! ", V.v.)? Trong đoạn mã trên, điều này được thực hiện bằng cách đơn giản gọi "GlyphName (* j)". Tôi đã tạo ra phương pháp này với một BASH-Script từ danh sách tìm thấy tại
http://www.jdawiseman.com/papers/trivia/character-entities.html
và nó trông như thế này
const std::string GlyphName(wchar_t UnicodeCodepoint)
{
switch(UnicodeCodepoint)
{
case 0x00A0: return "nonbreakingspace";
case 0x00A1: return "exclamdown";
case 0x00A2: return "cent";
...
}
}
Một vấn đề lớn Tôi đã bỏ ngỏ là chỉ này hoạt động miễn là bạn sử dụng tối đa 254 ký tự khác nhau từ cùng một phông chữ. Để sử dụng hơn 254 ký tự khác nhau, bạn sẽ phải tạo nhiều mã cho cùng một phông chữ. Bên trong pdf, các codepages khác nhau được thể hiện bằng các phông chữ khác nhau, vì vậy để chuyển đổi giữa các mã, bạn sẽ phải chuyển đổi phông chữ, mà về lý thuyết có thể thổi pdf lên một chút, nhưng tôi cho một, có thể sống với điều đó. ..
Ngoài việc gói các chuỗi bằng '()', bạn cũng có thể sử dụng '<>'. Trong gt/lt, bạn sử dụng số hex thay vì chữ cái. Ít hiệu quả hơn nhiều, nhưng bạn không cần lo lắng về việc trốn thoát. '': "Xin chào thế giới!" như một chuỗi Unicode-16. Bài viết của Plinth cũng rất quan trọng ... bạn PHẢI sử dụng FE FF. FFFE là xấu. Đối với một số lý do. :/ –