📄 qfontsubset.cpp
字号:
Q_ASSERT(!widths.isEmpty()); QFontEngine::Properties properties = fontEngine->properties(); QByteArray width; QPdf::ByteStream s(&width); QFixed scale = QFixed(1000)/emSquare; QFixed defWidth = widths[0]; //qDebug("defWidth=%d, scale=%f", defWidth.toInt(), scale.toReal()); for (int i = 0; i < nGlyphs(); ++i) { if (defWidth != widths[i]) defWidth = 0; } if (defWidth > 0) { s << "/DW " << (defWidth*scale).toInt(); } else { s << "/W ["; for (int g = 0; g < nGlyphs();) { QFixed w = widths[g]; int start = g; int startLinear = 0; ++g; while (g < nGlyphs()) { QFixed nw = widths[g]; if (nw == w) { if (!startLinear) startLinear = g - 1; } else { if (startLinear > 0 && g - startLinear >= 10) break; startLinear = 0; } w = nw; ++g; } // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1); if (g - startLinear < 10) startLinear = 0; int endnonlinear = startLinear ? startLinear : g; // qDebug(" startLinear=%x endnonlinear=%x", startLinear,endnonlinear); if (endnonlinear > start) { s << start << "["; for (int i = start; i < endnonlinear; ++i) s << (widths[i]*scale).toInt(); s << "]\n"; } if (startLinear) s << startLinear << g - 1 << (widths[startLinear]*scale).toInt() << "\n"; } s << "]\n"; } return width;}static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges){ if (++nranges > 100) { ts << nranges << "beginbfrange\n" << ranges << "endbfrange\n"; ranges = QByteArray(); nranges = 0; }}QVector<int> QFontSubset::getReverseMap() const{ QVector<int> reverseMap; reverseMap.resize(0x10000); for (uint i = 0; i < 0x10000; ++i) reverseMap[i] = 0; QGlyphLayout glyphs[10]; for (uint uc = 0; uc < 0x10000; ++uc) { QChar ch(uc); int nglyphs = 10; fontEngine->stringToCMap(&ch, 1, glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly); int idx = glyph_indices.indexOf(glyphs[0].glyph); if (idx >= 0 && !reverseMap.at(idx)) reverseMap[idx] = uc; } return reverseMap;}QByteArray QFontSubset::createToUnicodeMap() const{ QVector<int> reverseMap = getReverseMap(); QByteArray touc; QPdf::ByteStream ts(&touc); ts << "/CIDInit /ProcSet findresource begin\n" "12 dict begin\n" "begincmap\n" "/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n" "/CMapName /Adobe-Identity-UCS def\n" "/CMapType 2 def\n" "1 begincodespacerange\n" "<0000> <FFFF>\n" "endcodespacerange\n"; int nranges = 1; QByteArray ranges = "<0000> <0000> <0000>\n"; QPdf::ByteStream s(&ranges); char buf[5]; for (int g = 1; g < nGlyphs(); ) { int uc0 = reverseMap.at(g); if (!uc0) { ++g; continue; } int start = g; int startLinear = 0; ++g; while (g < nGlyphs()) { int uc = reverseMap[g]; // cmaps can't have the high byte changing within one range, so we need to break on that as well if (!uc || (g>>8) != (start >> 8)) break; if (uc == uc0 + 1) { if (!startLinear) startLinear = g - 1; } else { if (startLinear > 0 && g - startLinear >= 10) break; startLinear = 0; } uc0 = uc; ++g; } // qDebug("start=%x startLinear=%x g-1=%x",start,startLinear,g-1); if (g - startLinear < 10) startLinear = 0; int endnonlinear = startLinear ? startLinear : g; // qDebug(" startLinear=%x endnonlinear=%x", startLinear,endnonlinear); if (endnonlinear > start) { s << "<" << QPdf::toHex((ushort)start, buf) << "> <"; s << QPdf::toHex((ushort)(endnonlinear - 1), buf) << "> "; if (endnonlinear == start + 1) { s << "<" << QPdf::toHex((ushort)reverseMap[start], buf) << ">\n"; } else { s << "["; for (int i = start; i < endnonlinear; ++i) { s << "<" << QPdf::toHex((ushort)reverseMap[i], buf) << "> "; } s << "]\n"; } checkRanges(ts, ranges, nranges); } if (startLinear) { while (startLinear < g) { int len = g - startLinear; int uc_start = reverseMap[startLinear]; int uc_end = uc_start + len - 1; if ((uc_end >> 8) != (uc_start >> 8)) len = 256 - (uc_start & 0xff); s << "<" << QPdf::toHex((ushort)startLinear, buf) << "> <"; s << QPdf::toHex((ushort)(startLinear + len - 1), buf) << "> "; s << "<" << QPdf::toHex((ushort)reverseMap[startLinear], buf) << ">\n"; checkRanges(ts, ranges, nranges); startLinear += len; } } } if (nranges) { ts << nranges << "beginbfrange\n" << ranges << "endbfrange\n"; } ts << "endcmap\n" "CMapName currentdict /CMap defineresource pop\n" "end\n" "end\n"; return touc;}int QFontSubset::addGlyph(int index){ int idx = glyph_indices.indexOf(index); if (idx < 0) { idx = glyph_indices.size(); glyph_indices.append(index); } return idx;}// ------------------------------ Truetype generation ----------------------------------------------typedef qint16 F2DOT14;typedef quint32 Tag;typedef quint16 GlyphID;typedef quint16 Offset;class QTtfStream {public: QTtfStream(QByteArray &ba) : data((uchar *)ba.data()) { start = data; } QTtfStream &operator <<(quint8 v) { *data = v; ++data; return *this; } QTtfStream &operator <<(quint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; } QTtfStream &operator <<(quint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; } QTtfStream &operator <<(qint8 v) { *data = quint8(v); ++data; return *this; } QTtfStream &operator <<(qint16 v) { qToBigEndian(v, data); data += sizeof(v); return *this; } QTtfStream &operator <<(qint32 v) { qToBigEndian(v, data); data += sizeof(v); return *this; } QTtfStream &operator <<(qint64 v) { qToBigEndian(v, data); data += sizeof(v); return *this; } int offset() const { return data - start; } void setOffset(int o) { data = start + o; } void align4() { while (offset() & 3) { *data = '\0'; ++data; } }private: uchar *data; uchar *start;};struct QTtfTable { Tag tag; QByteArray data;};Q_DECLARE_TYPEINFO(QTtfTable, Q_MOVABLE_TYPE);struct qttf_head_table { qint32 font_revision; quint16 flags; qint64 created; qint64 modified; qint16 xMin; qint16 yMin; qint16 xMax; qint16 yMax; quint16 macStyle; qint16 indexToLocFormat;};struct qttf_hhea_table { qint16 ascender; qint16 descender; qint16 lineGap; quint16 maxAdvanceWidth; qint16 minLeftSideBearing; qint16 minRightSideBearing; qint16 xMaxExtent; quint16 numberOfHMetrics;};struct qttf_maxp_table { quint16 numGlyphs; quint16 maxPoints; quint16 maxContours; quint16 maxCompositePoints; quint16 maxCompositeContours; quint16 maxComponentElements; quint16 maxComponentDepth;};struct qttf_name_table { QString copyright; QString family; QString subfamily; QString postscript_name;};static QTtfTable generateHead(const qttf_head_table &head);static QTtfTable generateHhea(const qttf_hhea_table &hhea);static QTtfTable generateMaxp(const qttf_maxp_table &maxp);static QTtfTable generateName(const qttf_name_table &name);struct qttf_font_tables{ qttf_head_table head; qttf_hhea_table hhea; qttf_maxp_table maxp;};struct QTtfGlyph { quint16 index; qint16 xMin; qint16 xMax; qint16 yMin; qint16 yMax; quint16 advanceWidth; qint16 lsb; quint16 numContours; quint16 numPoints; QByteArray data;};Q_DECLARE_TYPEINFO(QTtfGlyph, Q_MOVABLE_TYPE);static QTtfGlyph generateGlyph(int index, const QPainterPath &path, qreal advance, qreal lsb, qreal ppem);// generates glyf, loca and hmtxstatic QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QList<QTtfGlyph> &_glyphs);static QByteArray bindFont(const QList<QTtfTable>& _tables);static quint32 checksum(const QByteArray &table){ quint32 sum = 0; int offset = 0; const uchar *d = (uchar *)table.constData(); while (offset <= table.size()-3) { sum += qFromBigEndian<quint32>(d + offset); offset += 4; } int shift = 24; quint32 x = 0; while (offset < table.size()) { x |= ((quint32)d[offset]) << shift; ++offset; shift -= 8; } sum += x; return sum;}static QTtfTable generateHead(const qttf_head_table &head){ const int head_size = 54; QTtfTable t; t.tag = MAKE_TAG('h', 'e', 'a', 'd'); t.data.resize(head_size); QTtfStream s(t.data);// qint32 Table version number 0x00010000 for version 1.0.// qint32 fontRevision Set by font manufacturer. s << qint32(0x00010000) << head.font_revision// quint32 checkSumAdjustment To compute: set it to 0, sum the entire font as quint32, then store 0xB1B0AFBA - sum. << quint32(0)// quint32 magicNumber Set to 0x5F0F3CF5. << quint32(0x5F0F3CF5)// quint16 flags Bit 0: Baseline for font at y=0;// Bit 1: Left sidebearing point at x=0;// Bit 2: Instructions may depend on point size;// Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear;// Bit 4: Instructions may alter advance width (the advance widths might not scale linearly);// Bits 5-10: These should be set according to Apple's specification . However, they are not implemented in OpenType.// Bit 11: Font data is 'lossless,' as a result of having been compressed and decompressed with the Agfa MicroType Express engine.// Bit 12: Font converted (produce compatible metrics)// Bit 13: Font optimised for ClearType// Bit 14: Reserved, set to 0// Bit 15: Reserved, set to 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -