From 405c6ff0dac1bd6fa385a0effccf69e14b8e2a59 Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Sun, 2 Jan 2022 23:14:17 +0100 Subject: [PATCH] PdfDraw: Fixed nonBMP glyphs export --- uppsrc/Draw/Draw.h | 4 ++ uppsrc/Draw/FontCR.cpp | 20 ++++++---- uppsrc/PdfDraw/PdfDraw.cpp | 7 +--- uppsrc/PdfDraw/PdfDraw.h | 14 +++---- uppsrc/PdfDraw/PdfDraw.upp | 2 +- uppsrc/PdfDraw/TTFReader.cpp | 71 +++++++++++------------------------- upptst/PdfEmoji/PdfEmoji.upp | 10 +++++ upptst/PdfEmoji/main.cpp | 12 ++++++ upptst/PdfText/PdfText.cpp | 2 +- upptst/PdfText2/PdfText.cpp | 27 ++++++++++++++ upptst/PdfText2/PdfText2.upp | 10 +++++ 11 files changed, 107 insertions(+), 72 deletions(-) create mode 100644 upptst/PdfEmoji/PdfEmoji.upp create mode 100644 upptst/PdfEmoji/main.cpp create mode 100644 upptst/PdfText2/PdfText.cpp create mode 100644 upptst/PdfText2/PdfText2.upp diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index 5f037ccff..bd8ed7789 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -978,6 +978,10 @@ IsJPGFnType GetIsJPGFn(); #include "DDARasterizer.h" #include "SDraw.h" +bool ReadCmap(const char *ptr, int count, Event range, bool glyphs); +bool ReadCmap(Font font, Event range, bool glyphs = false); +bool GetPanoseNumber(Font font, byte *panose); + } #endif diff --git a/uppsrc/Draw/FontCR.cpp b/uppsrc/Draw/FontCR.cpp index ae0a233dd..e139be401 100644 --- a/uppsrc/Draw/FontCR.cpp +++ b/uppsrc/Draw/FontCR.cpp @@ -234,20 +234,20 @@ struct sRFace { #include "Fonts.i" }; -bool ReadCmap(Font font, Event range, bool glyphs = false) { - String data = font.GetData("cmap"); - auto Get16 = [&](int i) { return i >= 0 && i + 2 <= data.GetCount() ? Peek16be(~data + i) : 0; }; - auto Get32 = [&](int i) { return i >= 0 && i + 4 <= data.GetCount() ? Peek32be(~data + i) : 0; }; +bool ReadCmap(const char *ptr, int count, Event range, bool glyphs) +{ + auto Get16 = [&](int i) { return i >= 0 && i + 2 <= count ? Peek16be(ptr + i) : 0; }; + auto Get32 = [&](int i) { return i >= 0 && i + 4 <= count ? Peek32be(ptr + i) : 0; }; for(int pass = 0; pass < 2; pass++) { int p = 0; p += 2; int n = Get16(p); p += 2; - while(n-- && p < data.GetCount()) { + while(n-- && p < count) { int pid = Get16(p); p += 2; int psid = Get16(p); p += 2; int offset = Get32(p); p += 4; - if(offset < 0 || offset > data.GetCount()) + if(offset < 0 || offset > count) return false; int format = Get16(offset); LLOG("cmap pid: " << pid << " psid: " << psid << " format: " << format); @@ -264,7 +264,7 @@ bool ReadCmap(Font font, Event range, bool glyphs = false) { return true; } else - if((pid == 3 && psid == 1) || (pid == 0 && psid == 3) && format == 4 && pass == 1) { + if(((pid == 3 && psid == 1) || (pid == 0 && psid == 3) && format == 4) && pass == 1) { int p = offset; int n = Get16(p + 6) >> 1; int seg_end = p + 14; @@ -300,6 +300,12 @@ bool ReadCmap(Font font, Event range, bool glyphs = false) { return false; } +bool ReadCmap(Font font, Event range, bool glyphs) +{ + String h = font.GetData("cmap"); + return ReadCmap(h, h.GetCount(), range, glyphs); +} + bool GetPanoseNumber(Font font, byte *panose) { memset(panose, 0, 10); diff --git a/uppsrc/PdfDraw/PdfDraw.cpp b/uppsrc/PdfDraw/PdfDraw.cpp index 80fd1ffa0..fe4cad37e 100644 --- a/uppsrc/PdfDraw/PdfDraw.cpp +++ b/uppsrc/PdfDraw/PdfDraw.cpp @@ -297,7 +297,7 @@ PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt) of.sitalic = of.ttf = false; TTFReader ttf; - if(ttf.Open(fnt.GetData(), false, true)) { + if(ttf.Open(fnt, false, true)) { of.ttf = true; of.sitalic = fnt.IsItalic() && (ttf.head.macStyle & 2) == 0; of.sbold = fnt.IsBold() && (ttf.head.macStyle & 1) == 0; @@ -906,11 +906,8 @@ String PdfDraw::Finish(const PdfSignatureInfo *sign) EndObj(); } else { - String fontbuffer; - fontbuffer = pdffont.GetKey(i).GetData(); - TTFReader ttf; - if(!ttf.Open(fontbuffer)) + if(!ttf.Open(pdffont.GetKey(i))) return Null; String name = FormatIntAlpha(i + 1, true); diff --git a/uppsrc/PdfDraw/PdfDraw.h b/uppsrc/PdfDraw/PdfDraw.h index fc4264c60..29096f328 100644 --- a/uppsrc/PdfDraw/PdfDraw.h +++ b/uppsrc/PdfDraw/PdfDraw.h @@ -55,16 +55,16 @@ class TTFReader { virtual ~TTFStreamOut() {} }; - String font; + Font font; + String current_table; struct Table : Moveable { int offset; int length; }; VectorMap table; - - word zero[256]; - word *cmap[256]; + + VectorMap glyph_map; struct GlyphInfo : Moveable { int offset; @@ -92,7 +92,6 @@ class TTFReader { int Read32(const char *&s); String Read(const char *&s, int n); - void Free(); void Reset(); const char *Seek(const char *tab, int& len); @@ -217,14 +216,13 @@ public: Post post; String ps_name; - int GetGlyph(wchar chr) { return cmap[HIBYTE(chr)][LOBYTE(chr)]; } + int GetGlyph(wchar chr) { return glyph_map.Get(chr, 0); } word GetAdvanceWidth(wchar chr) { return glyphinfo[GetGlyph(chr)].advanceWidth; } String Subset(const Vector& chars, int first = 0, bool os2 = false); - bool Open(const String& fnt, bool symbol = false, bool justcheck = false); + bool Open(const Font& fnt, bool symbol = false, bool justcheck = false); TTFReader(); - ~TTFReader(); }; struct PdfSignatureInfo { diff --git a/uppsrc/PdfDraw/PdfDraw.upp b/uppsrc/PdfDraw/PdfDraw.upp index 89e32929a..4e07d9743 100644 --- a/uppsrc/PdfDraw/PdfDraw.upp +++ b/uppsrc/PdfDraw/PdfDraw.upp @@ -7,8 +7,8 @@ file PdfDraw.h options(BUILDER_OPTION) PCH, TTFStream.cpp, TTFStruct.cpp, - TTFReader.cpp, TTFSubset.cpp, + TTFReader.cpp, ICCColorSpace.i, PdfDraw.cpp, PdfReport.cpp, diff --git a/uppsrc/PdfDraw/TTFReader.cpp b/uppsrc/PdfDraw/TTFReader.cpp index 95eac8bba..923a7848e 100644 --- a/uppsrc/PdfDraw/TTFReader.cpp +++ b/uppsrc/PdfDraw/TTFReader.cpp @@ -7,21 +7,21 @@ namespace Upp { int TTFReader::Peek8(const char *s) { - if(s + 1 > font.End()) + if(s + 1 > current_table.End()) Error(); return (byte)*s; } int TTFReader::Peek16(const char *s) { - if(s + 2 > font.End()) + if(s + 2 > current_table.End()) Error(); return ((byte)s[0] << 8) | (byte)s[1]; } int TTFReader::Peek32(const char *s) { - if(s + 4 > font.End()) + if(s + 4 > current_table.End()) Error(); return ((byte)s[0] << 24) | ((byte)s[1] << 16) | ((byte)s[2] << 8) | (byte)s[3]; } @@ -58,7 +58,7 @@ int TTFReader::Read32(const char *&s) String TTFReader::Read(const char *&s, int n) { - if(s + n > font.End()) + if(s + n > current_table.End()) Error(); String q(s, n); s += n; @@ -67,34 +67,20 @@ String TTFReader::Read(const char *&s, int n) void TTFReader::Reset() { - memset(zero, 0, sizeof(zero)); - for(int i = 0; i < 256; i++) - cmap[i] = zero; -} - -void TTFReader::Free() -{ - for(int i = 0; i < 256; i++) - if(cmap[i] != zero) - delete[] cmap[i]; + glyph_map.Clear(); } void TTFReader::SetGlyph(wchar chr, word glyph) { - int h = HIBYTE(chr); - if(cmap[h] == zero) - memset(cmap[h] = new word[256], 0, 256 * sizeof(word)); - cmap[h][LOBYTE(chr)] = glyph; + glyph_map.GetAdd(chr) = glyph; } const char *TTFReader::Seek(const char *tab, int& len) { ASSERT(strlen(tab) == 4); - int q = table.Find(tab); - if(q < 0) - Error(); - len = table[q].length; - return ~font + table[q].offset; + current_table = font.GetData(tab); + len = current_table.GetCount(); + return current_table; } const char *TTFReader::Seek(const char *tab) @@ -113,35 +99,17 @@ void TTFReader::Seek(const char *tab, TTFStreamIn& s) String TTFReader::GetTable(const char *tab) { ASSERT(strlen(tab) == 4); - int q = table.Find(tab); - if(q < 0) - return Null; - return String(~font + table[q].offset, table[q].length); + return font.GetData(tab); } -bool TTFReader::Open(const String& fnt, bool symbol, bool justcheck) +bool TTFReader::Open(const Font& fnt, bool symbol, bool justcheck) { try { int i; - Free(); Reset(); table.Clear(); glyphinfo.Clear(); font = fnt; - const char *s = fnt; - int q = Read32(s); - if(q != 0x74727565 && q != 0x00010000) - Error(); - int n = Read16(s); - s += 6; - while(n--) { - Table& t = table.Add(Read(s, 4)); - s += 4; - t.offset = Read32(s); - t.length = Read32(s); - } - for(i = 0; i < table.GetCount(); i++) - LLOG("table: " << table.GetKey(i) << " offset: " << table[i].offset << " length: " << table[i].length); TTFStreamIn is; Seek("head", is); @@ -186,7 +154,7 @@ bool TTFReader::Open(const String& fnt, bool symbol, bool justcheck) glyphinfo.SetCount(maxp.numGlyphs); - s = Seek("hmtx"); + const char *s = Seek("hmtx"); int aw = 0; for(i = 0; i < hhea.numOfLongHorMetrics; i++) { aw = glyphinfo[i].advanceWidth = (uint16)Read16(s); @@ -212,6 +180,14 @@ bool TTFReader::Open(const String& fnt, bool symbol, bool justcheck) LLOG(i << " advance: " << glyphinfo[i].advanceWidth << ", left: " << glyphinfo[i].leftSideBearing << ", offset: " << glyphinfo[i].offset << ", size: " << glyphinfo[i].size); + int len; + const char *cmap = Seek("cmap", len); + ReadCmap(cmap, len, [&](int start, int end, int glyph) { + for(int ch = start; ch <= end; ch++) + SetGlyph(ch, glyph++); + }, true); + + #if 0 s = Seek("cmap"); const char *p = s; p += 2; @@ -262,7 +238,7 @@ bool TTFReader::Open(const String& fnt, bool symbol, bool justcheck) break; } } - + #endif const char *strings = Seek("name"); s = strings + 2; @@ -303,9 +279,4 @@ TTFReader::TTFReader() Reset(); } -TTFReader::~TTFReader() -{ - Free(); -} - } diff --git a/upptst/PdfEmoji/PdfEmoji.upp b/upptst/PdfEmoji/PdfEmoji.upp new file mode 100644 index 000000000..1d2cdd1a1 --- /dev/null +++ b/upptst/PdfEmoji/PdfEmoji.upp @@ -0,0 +1,10 @@ +uses + CtrlLib, + PdfDraw; + +file + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/upptst/PdfEmoji/main.cpp b/upptst/PdfEmoji/main.cpp new file mode 100644 index 000000000..9f2cab72a --- /dev/null +++ b/upptst/PdfEmoji/main.cpp @@ -0,0 +1,12 @@ +#include +#include +#include + +using namespace Upp; + +GUI_APP_MAIN +{ + String p = GetHomeDirFile("pdf.pdf"); + SaveFile(p, Pdf(ParseQTF("Some emojis: ðŸĪĢ ðŸ˜‡ 🙂 🙃 😉 😌 😍 ðŸĨ° 😘 😗 😙 😚 😋 😛 😝 😜 ðŸĪŠ"))); + LaunchWebBrowser(p); +} diff --git a/upptst/PdfText/PdfText.cpp b/upptst/PdfText/PdfText.cpp index 2b52cb26f..76f76cbbd 100644 --- a/upptst/PdfText/PdfText.cpp +++ b/upptst/PdfText/PdfText.cpp @@ -6,7 +6,7 @@ CONSOLE_APP_MAIN { PdfDraw pdf; int cy = 0; - for(int face = Font::SERIF; face < min(9, Font::GetFaceCount()); face++) + for(int face = Font::SERIF; face < min(20, Font::GetFaceCount()); face++) // int face = 6; for(int strikeout = 0; strikeout < 2; strikeout++) for(int underline = 0; underline < 2; underline++) diff --git a/upptst/PdfText2/PdfText.cpp b/upptst/PdfText2/PdfText.cpp new file mode 100644 index 000000000..2f89c5d69 --- /dev/null +++ b/upptst/PdfText2/PdfText.cpp @@ -0,0 +1,27 @@ +#include + +using namespace Upp; + +CONSOLE_APP_MAIN +{ + PdfDraw pdf; + int cy = 0; + for(int face = Font::SERIF; face < Font::GetFaceCount(); face++) { + Font fnt(face, 100); + Cout() << fnt << "\n"; + LOG(face << ' ' << fnt << ", TTF: " << fnt.IsTrueType()); + if(1 || fnt.IsTrueType()) { + pdf.DrawText(0, cy, AsString(fnt), fnt, Black); + pdf.DrawText(200, cy, AsString(fnt), StdFont(100), Black); + cy += fnt.GetLineHeight(); + if(cy > 6000) { + pdf.EndPage(); + pdf.StartPage(); + cy = 0; + } + } + } + String p = GetHomeDirFile("pdf.pdf"); + SaveFile(p, pdf.Finish()); + LaunchWebBrowser(p); +} diff --git a/upptst/PdfText2/PdfText2.upp b/upptst/PdfText2/PdfText2.upp new file mode 100644 index 000000000..b22df9307 --- /dev/null +++ b/upptst/PdfText2/PdfText2.upp @@ -0,0 +1,10 @@ +uses + Core, + PdfDraw; + +file + PdfText.cpp; + +mainconfig + "" = ""; +