Annotation of nono/util/ttfext/ttfext.cpp, revision 1.1.1.1

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2022 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // TTF から埋め込みビットマップを抜き出して BDF にする。
                      9: //
                     10: 
                     11: // TTF の構造についてはこの辺参照。
                     12: // - https://learn.microsoft.com/en-us/typography/opentype/spec/ > Tables
                     13: //
                     14: // - OpenType ファイル構造
                     15: //   https://aznote.jakou.com/prog/opentype/02_struct.html
                     16: 
                     17: #include "header.h"
                     18: #include "autofd.h"
                     19: #include "mystring.h"
                     20: #include <errno.h>
                     21: #include <fcntl.h>
                     22: #include <iconv.h>
                     23: #include <unistd.h>
                     24: #include <vector>
                     25: 
                     26: #define HOWMANY(x, y)  (((x) + (y - 1)) / (y))
                     27: 
                     28: static constexpr uint32
                     29: FOURCC(const char *str)
                     30: {
                     31:        return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3];
                     32: }
                     33: 
                     34: static int debug = 1;
                     35: static const char *new_family_name;
                     36: 
                     37: //
                     38: // ファイルアクセス
                     39: //
                     40: class File
                     41: {
                     42:  public:
                     43:        File() {
                     44:                fd = -1;
                     45:        }
                     46:        File(const File& rhs) {
                     47:                fd = rhs.fd;
                     48:        }
                     49:        ~File() {
                     50:                Close();
                     51:        }
                     52: 
                     53:        bool Create(const std::string& filename_) {
                     54:                filename = filename_;
                     55:                fd = open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644);
                     56:                if (fd < 0) {
                     57:                        err(1, "open: %s", filename.c_str());
                     58:                }
                     59:                return true;
                     60:        }
                     61:        bool Open(const std::string& filename_) {
                     62:                filename = filename_;
                     63:                fd = open(filename.c_str(), O_RDONLY);
                     64:                if (fd < 0) {
                     65:                        err(1, "open: %s", filename.c_str());
                     66:                }
                     67:                return true;
                     68:        }
                     69: 
                     70:        void Close() {
                     71:                if (fd >= 0) {
                     72:                        close(fd);
                     73:                }
                     74:        }
                     75: 
                     76:        ssize_t Read(void *buf, size_t len) {
                     77:                auto r = read(fd, buf, len);
                     78:                if (r < 0) {
                     79:                        err(1, "File.Read(%d)", fd);
                     80:                }
                     81:                return r;
                     82:        }
                     83: 
                     84:        ssize_t Write(const void *buf, size_t len) {
                     85:                auto r = write(fd, buf, len);
                     86:                if (r < 0) {
                     87:                        err(1, "File.Write(%d)", fd);
                     88:                }
                     89:                return r;
                     90:        }
                     91: 
                     92:        // TTF はビッグエンディアンなので、専用読み込みルーチンを用意
                     93:        uint8 Read8() {
                     94:                uint8 buf[1];
                     95:                Read(&buf, sizeof(buf));
                     96:                return buf[0];
                     97:        }
                     98: 
                     99:        uint16 Read16() {
                    100:                uint8 buf[2];
                    101:                Read(&buf, sizeof(buf));
                    102:                return (buf[0] << 8) | buf[1];
                    103:        }
                    104: 
                    105:        uint32 Read32() {
                    106:                uint8 buf[4];
                    107:                Read(&buf, sizeof(buf));
                    108:                return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
                    109:        }
                    110: 
                    111:        // 便利用
                    112:        ssize_t Write(const std::string& str) {
                    113:                return Write(str.data(), str.length());
                    114:        }
                    115: 
                    116:        ssize_t Print(const char *fmt, ...) {
                    117:                char buf[1024];
                    118:                va_list ap;
                    119:                va_start(ap, fmt);
                    120:                vsnprintf(buf, sizeof(buf), fmt, ap);
                    121:                va_end(ap);
                    122:                return Write(buf, strlen(buf));
                    123:        }
                    124: 
                    125:        off_t Seek(off_t off) {
                    126:                auto r = lseek(fd, off, SEEK_SET);
                    127:                if (r < 0) {
                    128:                        err(1, "File.Seek(%d, %jd)", fd, (intmax_t)off);
                    129:                }
                    130:                return r;
                    131:        }
                    132: 
                    133:        off_t Tell() const {
                    134:                auto r = lseek(fd, 0, SEEK_CUR);
                    135:                if (r < 0) {
                    136:                        err(1, "File.Tell(%d)", fd);
                    137:                }
                    138:                return r;
                    139:        }
                    140: 
                    141:        const std::string& GetName() const { return filename; }
                    142: 
                    143:  private:
                    144:        int fd {};
                    145:        std::string filename {};
                    146: };
                    147: 
                    148: // UTF-16 文字列 srcbuf を UTF-8 文字列に変換して返す。
                    149: // from はエンコーディング名で "utf-16be" とか。
                    150: // UTF-16 は '\0' を含むので std::string が使えず他のエンコーディングの
                    151: // 場合と共通化しづらい。
                    152: static std::string
                    153: FromUTF16(const char *from, const std::vector<uint8>& srcbuf)
                    154: {
                    155:        const char *to = "utf-8";
                    156:        auto cd = iconv_open(to, from);
                    157:        if (cd == (iconv_t)-1) {
                    158:                err(1, "iconv_open(%s, %s)", to, from);
                    159:        }
                    160: 
                    161:        const char *src = (const char *)&srcbuf[0];
                    162:        size_t srcleft = srcbuf.size();
                    163:        std::vector<char> dstbuf(srcbuf.size() * 3);    // 適当
                    164:        char *dst = &dstbuf[0];
                    165:        size_t dstleft = dstbuf.size();
                    166: 
                    167:        auto r = ICONV(cd, &src, &srcleft, &dst, &dstleft);
                    168:        iconv_close(cd);
                    169:        if (r == (size_t)-1 && errno != EILSEQ) {
                    170:                err(1, "iconv failed");
                    171:        }
                    172: 
                    173:        dst[dstbuf.size() - dstleft] = '\0';
                    174:        return std::string(dstbuf.data());
                    175: }
                    176: 
                    177: 
                    178: //
                    179: // ここから TTF
                    180: //
                    181: 
                    182: struct NameRecord
                    183: {
                    184:        uint16 platformID;
                    185:        uint16 encodingID;
                    186:        uint16 languageID;
                    187:        uint16 nameID;
                    188:        uint16 length;
                    189:        uint16 stringOffset;
                    190: 
                    191:        std::string name;
                    192: 
                    193:        // nameID の表示用文字列を返す
                    194:        std::string GetNameIDStr() const {
                    195:                return GetNameIDStr(nameID);
                    196:        }
                    197:        static std::string GetNameIDStr(uint id);
                    198: };
                    199: 
                    200: // 各パラメータの意味はここのサイトの中ほどにある g の図参照。
                    201: // https://learn.microsoft.com/en-us/typography/opentype/spec/eblc
                    202: //
                    203: // horiAdvance, vertAdvance が要するにフォントサイズ。
                    204: struct BigGlyphMetrics
                    205: {
                    206:        uint8 height;           // Number of rows of data.
                    207:        uint8 width;            // Number of columns of data.
                    208:        int8  horiBearingX;     // Distance in pixels from the horizontal origin to
                    209:                                                // the left edge of the bitmap.
                    210:        int8  horiBearingY;     // Distance in pixels from the horizontal origin to
                    211:                                                // the top edge of the bitmap.
                    212:        uint8 horiAdvance;      // Horizontal advance width in pixels.
                    213:        int8  vertBearingX;     // Distance in pixels from the vertical origin to
                    214:                                                // the left edge of the bitmap.
                    215:        int8  vertBearingY;     // Distance in pixels from the vertical origin to
                    216:                                                // the top edge of the bitmap.
                    217:        uint8 vertAdvance;      // Vertical advance width in pixels.
                    218: 
                    219:        // file からこの構造体をロードする
                    220:        void Load(File& file);
                    221: };
                    222: 
                    223: // IndexSubTable にいろいろ混ぜてしまう。
                    224: class IndexSubTable
                    225: {
                    226:  public:
                    227:        // indexSubTable
                    228:        uint16 firstGlyphIndex;
                    229:        uint16 lastGlyphIndex;
                    230:        uint32 additionalOffsetToIndexSubTable; // サブテーブルまでのオフセット
                    231: 
                    232:        // indexSubHeader
                    233:        uint16 indexFormat;                             // Format of this IndexSubTable.
                    234:        uint16 imageFormat;                             // Format of EBDT image data.
                    235:        uint32 imageDataOffset;                 // Offset to image data in EBDT table.
                    236: 
                    237:        // indexSubTable1
                    238:        // first..last までの何かの EBDT 内でのオフセット
                    239:        std::vector<uint32> sbitOffset;
                    240: 
                    241:        // indexSubTable2
                    242:        uint32 imageSize;                               // All the glyphs are of the same size.
                    243:        BigGlyphMetrics bigMetrics;             // All glyphs have the same metrics;
                    244:                                                                        // glyph data may be compressed,
                    245:                                                                        // byte-aligned, or bit-aligned.
                    246: };
                    247: 
                    248: class SbitLineMetrics
                    249: {
                    250:  public:
                    251:        int8  ascender;
                    252:        int8  descender;        // 上を正として、ベースラインからの距離。なので負。
                    253:        uint8 widthMax;
                    254:        int8  caretSlopeNumerator;
                    255:        int8  caretSlopeDenominator;
                    256:        int8  caretOffset;
                    257:        int8  minOriginSB;
                    258:        int8  minAdvanceSB;
                    259:        int8  maxBeforeBL;
                    260:        int8  minAfterBL;
                    261:        int8  pad1;
                    262:        int8  pad2;
                    263: 
                    264:        // file からこの構造体をロードする
                    265:        void Load(File& file);
                    266: };
                    267: 
                    268: class BitmapSize
                    269: {
                    270:  public:
                    271:        // flags。BigGlyphMetrics とかで使う。
                    272:        enum {
                    273:                HORIZONTAL_METRICS      = 0x01,
                    274:                VERTICAL_METRICS        = 0x02,
                    275:        };
                    276: 
                    277:  public:
                    278:        uint32 indexSubTableArrayOffset;
                    279:        uint32 indexTablesSize;
                    280:        uint32 numberOfIndexSubTables;
                    281:        uint32 colorRef;
                    282:        SbitLineMetrics hori;
                    283:        SbitLineMetrics vert;
                    284:        uint16 startGlyphIndex;
                    285:        uint16 endGlyphIndex;
                    286:        uint8 ppemX;
                    287:        uint8 ppemY;
                    288:        uint8 bitDepth;
                    289:        uint8 flags;
                    290: 
                    291:        std::vector<IndexSubTable> indexSubTable {};
                    292: };
                    293: 
                    294: class EncodingRecord
                    295: {
                    296:  public:
                    297:        uint16 platformID;
                    298:        uint16 encodingID;
                    299:        uint32 subtableOffset;
                    300: 
                    301:        std::string ToString() const;
                    302: };
                    303: 
                    304: class CMAPSubTableFormat4
                    305: {
                    306:  public:
                    307:        uint16 format;                                  // Format number is set to 4.
                    308: 
                    309:        uint16 length;                                  // This is the length in bytes of the
                    310:                                                                        // subtable.
                    311:        uint16 language;
                    312:        uint16 segCountX2;                              // 2 × segCount.
                    313: 
                    314:        uint16 searchRange;                             // Maximum power of 2 less than or
                    315:                                                                        // equal to segCount,
                    316:                                                                        // times 2 ((2**floor(log2(segCount))) * 2
                    317: 
                    318:        uint16 entrySelector;                   // Log_2 of the maximum power of 2 less
                    319:                                                                        // than or equal to numTables
                    320:                                                                        // (log2(searchRange/2),
                    321:                                                                        // which is equal to floor(log2(segCount)))
                    322: 
                    323:        uint16 rangeShift;                              // segCount times 2, minus searchRange
                    324:                                                                        // ((segCount * 2) - searchRange)
                    325: 
                    326:        std::vector<uint16> endCode;    // End characterCode for each segment,
                    327:                                                                        // last=0xFFFF.
                    328: 
                    329:        std::vector<uint16> startCode;  // Start character code for each segment.
                    330:        std::vector<int16>  idDelta;    // Delta for all character codes in segment.
                    331:        std::vector<uint16> idRangeOffsets;
                    332:                                                                        // Offsets into glyphIdArray or 0
                    333:        std::vector<uint16> glyphIdArray;
                    334:                                                                        // Glyph index array (arbitrary length)
                    335: };
                    336: 
                    337: enum NameID
                    338: {
                    339:        Copyright = 0,
                    340:        FontFamilyName,
                    341:        FontSubfamilyName,
                    342:        UniqueFontIdentifier,
                    343:        FullFontName,
                    344:        VersionString,
                    345:        PostScriptName,
                    346:        Trademark,
                    347:        ManufacturerName,
                    348:        Designer,
                    349:        Description,
                    350:        URLVendor,
                    351:        URLDesigner,
                    352:        LicenseDescription,
                    353:        LicenseInfoURL,
                    354:        reserved,
                    355:        TypoGraphicFamilyName,
                    356:        TypographicSubfamilyName,
                    357:        CompatibleFull,
                    358:        SampleText,
                    359:        PostScriptCIDFindfontName,
                    360:        WWSFamilyName,
                    361:        WWSSubfamilyName,
                    362:        LightBackgroundPalette,
                    363:        DarkBackgroundPalette,
                    364:        VariationsPostScriptNamePrefix,
                    365: };
                    366: 
                    367: class TTF_name
                    368: {
                    369:        enum {
                    370:                Platform_Unicode = 0,
                    371:                Platform_Macintosh = 1,
                    372:                Platform_Windows = 3,
                    373:        };
                    374: 
                    375:  public:
                    376:        TTF_name(File& file, off_t offset);
                    377: 
                    378:        // 指定の NameID の値を取得する
                    379:        std::string GetName(NameID id) const;
                    380: 
                    381:  private:
                    382:        static std::string GetPlatformIDStr(uint id);
                    383: 
                    384:        std::vector<NameRecord> nameRecord {};
                    385: };
                    386: 
                    387: class TTF_EBLC
                    388: {
                    389:  public:
                    390:        TTF_EBLC(const File& file_, off_t offset);
                    391: 
                    392:        std::vector<BitmapSize> bitmapSizes {};
                    393: 
                    394:        // グリフ数を返す
                    395:        int GetGlyphCount() const { return endGlyphIndex - startGlyphIndex + 1; }
                    396:        // フォントパラメータを返す
                    397:        int GetFontsize() const { return fontsize; }
                    398:        int GetAscent() const   { return ascent; }
                    399:        int GetDescent() const  { return descent; }
                    400: 
                    401:  private:
                    402:        File file {};
                    403: 
                    404:        uint startGlyphIndex {};
                    405:        uint endGlyphIndex {};
                    406:        uint fontsize {};
                    407:        int  ascent {};
                    408:        int  descent {};                // 正数とする
                    409: };
                    410: 
                    411: 
                    412: class TTF_EBDT
                    413: {
                    414:  public:
                    415:        TTF_EBDT(const File& file_, off_t offset);
                    416: };
                    417: 
                    418: class TTF_cmap
                    419: {
                    420:  public:
                    421:        TTF_cmap(const File& file_, off_t offset);
                    422: 
                    423:        void MakeASCIIMap(std::vector<uint>& asciimap);
                    424:        void MakeJISMap(std::vector<uint>& jismap);
                    425: 
                    426:  private:
                    427:        int Code2GID(int code) const;
                    428: 
                    429:        File file {};
                    430:        std::vector<EncodingRecord> encodingRecords {};
                    431:        CMAPSubTableFormat4 sub;
                    432: };
                    433: 
                    434: 
                    435: //
                    436: // TTF を扱うクラス。
                    437: // フィールド名などは概ね公式ドキュメントに従う。
                    438: //
                    439: class TTFFile
                    440: {
                    441:        static const uint32 NAME_name = FOURCC("name");
                    442:        static const uint32 NAME_EBDT = FOURCC("EBDT");
                    443:        static const uint32 NAME_EBLC = FOURCC("EBLC");
                    444:        static const uint32 NAME_cmap = FOURCC("cmap");
                    445: 
                    446:  public:
                    447:        TTFFile();
                    448:        ~TTFFile();
                    449: 
                    450:        bool Open(const File& file_);
                    451:        void SaveBDFAscii(File& outfile);
                    452:        void SaveBDFKanji(File& outfile);
                    453: 
                    454:        // ASCII から GID への変換テーブル
                    455:        std::vector<uint> asciimap {};
                    456:        // JIS から GID への変換テーブル
                    457:        std::vector<uint> jismap {};
                    458: 
                    459:        // グリフデータ。GID => data[]
                    460:        std::vector<std::vector<uint8>> glyph {};
                    461: 
                    462:  private:
                    463:        void LoadGlyph();
                    464:        void LoadGlyphFormat1_7(const IndexSubTable& sub);
                    465:        void LoadGlyphFormat2_5(const IndexSubTable& sub);
                    466:        std::string DebugBitmapData(int, const std::vector<uint8>& data);
                    467:        void WriteBDFHeader(File& outfile, int width);
                    468:        std::string MakeChar(uint code, int, int, const std::vector<uint8>& data);
                    469: 
                    470:        File file {};
                    471:        std::unique_ptr<TTF_name> name {};
                    472:        std::unique_ptr<TTF_EBLC> eblc {};
                    473:        std::unique_ptr<TTF_cmap> cmap {};
                    474:        int fontsize {};
                    475:        int ascent {};
                    476:        int descent {};         // 正数とする
                    477: 
                    478:        uint32 offset_name {};
                    479:        uint32 offset_EBDT {};
                    480:        uint32 offset_EBLC {};
                    481:        uint32 offset_cmap {};
                    482: };
                    483: 
                    484: // コンストラクタ
                    485: TTFFile::TTFFile()
                    486: {
                    487:        asciimap.resize(256);
                    488:        // JIS は上位下位とも (0x21 .. 0x7e) の範囲
                    489:        jismap.resize(0x5e * 0x5e);
                    490: }
                    491: 
                    492: // デストラクタ
                    493: TTFFile::~TTFFile()
                    494: {
                    495: }
                    496: 
                    497: // ファイルから情報を取得
                    498: bool
                    499: TTFFile::Open(const File& file_)
                    500: {
                    501:        file = file_;
                    502: 
                    503:        // 先頭のファイルヘッダ(オフセットテーブルというらしい)は 12バイト
                    504:        uint32 version = file.Read32();
                    505:        uint32 numTables = file.Read16();
                    506:        uint32 searchRange __unused = file.Read16();
                    507:        uint32 entrySelector __unused = file.Read16();
                    508:        uint32 rangeShift __unused = file.Read16();
                    509:        if (debug) {
                    510:                printf("version = %08x\n", version);
                    511:                printf("numTables = %d\n", numTables);
                    512:        }
                    513: 
                    514:        // テーブルを調べて、必要なセクションの開始位置を取得
                    515:        for (int i = 0; i < numTables; i++) {
                    516:                uint32_t namecc = file.Read32();
                    517:                uint32_t csum   = file.Read32();
                    518:                uint32_t offset = file.Read32();
                    519:                uint32_t len = file.Read32();
                    520: 
                    521:                (void)csum;
                    522: 
                    523:                if (debug) {
                    524:                        printf("[%d] %c%c%c%c off=%08x len=%08x\n",
                    525:                                i,
                    526:                                (namecc >> 24),
                    527:                                (namecc >> 16) & 0xff,
                    528:                                (namecc >> 8)  & 0xff,
                    529:                                (namecc)       & 0xff,
                    530:                                offset,
                    531:                                len);
                    532:                }
                    533: 
                    534:                if (namecc == NAME_name) {
                    535:                        offset_name = offset;
                    536:                }
                    537:                if (namecc == NAME_EBDT) {
                    538:                        offset_EBDT = offset;
                    539:                }
                    540:                if (namecc == NAME_EBLC) {
                    541:                        offset_EBLC = offset;
                    542:                }
                    543:                if (namecc == NAME_cmap) {
                    544:                        offset_cmap = offset;
                    545:                }
                    546:        }
                    547: 
                    548:        // 必要なセクションが全部揃ってなければエラー終了
                    549:        if (offset_name == 0) {
                    550:                errx(1, "%s: no name section", file.GetName().c_str());
                    551:        }
                    552:        if (offset_EBDT == 0) {
                    553:                errx(1, "%s: no EBDT section", file.GetName().c_str());
                    554:        }
                    555:        if (offset_EBLC == 0) {
                    556:                errx(1, "%s: no EBLC section", file.GetName().c_str());
                    557:        }
                    558:        if (offset_cmap == 0) {
                    559:                errx(1, "%s: no cmap section", file.GetName().c_str());
                    560:        }
                    561: 
                    562:        // name セクションの読み込み。
                    563:        // name セクションは Copyright などのプロパティなど。
                    564:        name.reset(new TTF_name(file, offset_name));
                    565: 
                    566:        // EBLC セクションの読み込み。
                    567:        // EBLC セクションはビットマップグリフに関する情報(サイズや格納方法)。
                    568:        eblc.reset(new TTF_EBLC(file, offset_EBLC));
                    569:        fontsize = eblc->GetFontsize();
                    570:        ascent   = eblc->GetAscent();
                    571:        descent  = eblc->GetDescent();
                    572:        // それによってグリフ領域を確保。
                    573:        glyph.resize(eblc->GetGlyphCount());
                    574: 
                    575:        // cmap セクションの読み込み。
                    576:        // cmap セクションは文字コードと GID(内部のGlyph ID) とのマッピングなど。
                    577:        cmap.reset(new TTF_cmap(file, offset_cmap));
                    578: 
                    579:        // グリフインデックスを求める。
                    580:        cmap->MakeASCIIMap(asciimap);
                    581:        cmap->MakeJISMap(jismap);
                    582: 
                    583:        // EBDT セクションからフォントデータを読み込み。
                    584:        // EBDT セクションはほぼビットマップデータ置き場。
                    585:        LoadGlyph();
                    586: 
                    587:        return true;
                    588: }
                    589: 
                    590: // eblc で列挙されているすべてのグリフを読み込む。
                    591: void
                    592: TTFFile::LoadGlyph()
                    593: {
                    594:        // bitmapSizez[]->indexSubTable[] の2段階のテーブル。
                    595:        for (const auto& bs : eblc->bitmapSizes) {
                    596:                for (const auto& sub : bs.indexSubTable) {
                    597:                        // indexFormat はグリフのパラメータを持っているこのインデックス
                    598:                        // 自体が (共用体のようになっていて) どの形式かを示している。
                    599:                        // imageFormat は EBDT 内のグリフデータがどの形式かを示している。
                    600:                        // indexFormat と imageFormat は対象のグリフの性質によって
                    601:                        // ある程度組み合わせが決まっている。
                    602:                        if (sub.indexFormat == 1 && sub.imageFormat == 7) {
                    603:                                LoadGlyphFormat1_7(sub);
                    604:                        } else if (sub.indexFormat == 2 && sub.imageFormat == 5) {
                    605:                                LoadGlyphFormat2_5(sub);
                    606:                        } else {
                    607:                                // 他の組み合わせは出てこないので無視
                    608:                                errx(1, "Unsupported index=%d image=%d format",
                    609:                                        sub.indexFormat, sub.imageFormat);
                    610:                        }
                    611:                }
                    612:        }
                    613: }
                    614: 
                    615: // indexFormat=1, imageFormat=7
                    616: void
                    617: TTFFile::LoadGlyphFormat1_7(const IndexSubTable& sub)
                    618: {
                    619:        if (sub.lastGlyphIndex - sub.firstGlyphIndex + 1 != sub.sbitOffset.size()) {
                    620:                errx(1, "sbitOffset mismatch?");
                    621:        }
                    622: 
                    623:        // indexFormat==1 は
                    624:        // GlyphIndex の数分 sbitOffset[] で EBDT 内オフセットが指定してある。
                    625:        //
                    626:        // 例えば
                    627:        //  firstGlyphIndex = 0
                    628:        //  lastGlyphIndex  = 2
                    629:        //  imageDataOffset = 00000004
                    630:        //  sbitOffset[]    = { 00000000, 0000000c, 00000015 }
                    631:        // の場合、グリフデータは EBDT 先頭から数えて
                    632:        // GID=0 は $00000004+$00000000 = $00000004 から
                    633:        // GID=1 は $00000004+$0000000c = $00000010 から
                    634:        // GID=2 は $00000004+$00000015 = $00000019 から
                    635:        // 始まる。
                    636:        //
                    637:        // imageFormat==7 は "big metrics, bit-aligned data" 形式で、EBDT 内の
                    638:        // 指定オフセットの位置には
                    639:        //  BigGlyphMetrics bigMetrics;
                    640:        //  uint8           imageData[];
                    641:        // が記録されている。
                    642:        //
                    643:        // 例えば三点リーダのような疎なグリフに有効で、
                    644:        // BigGlyphMetrics でオフセットが指定されており、
                    645:        // imageData[] は実際の描画点のある下図中枠の部分だけでよい、という構造。
                    646:        //
                    647:        //   BigGlyphMetrics.horiBearingX
                    648:        //   |->|
                    649:        //   +-------------+
                    650:        //   |             |
                    651:        //   |  +-------+  |---
                    652:        //   |  |X  X  X|  | ^
                    653:        //   |  +-------+  | | BigGlyphMetrics.horiBearingY
                    654:        //   |             | |
                    655:        //   +-------------+--- Baseline
                    656:        //   |             |
                    657:        //   +-------------+
                    658: 
                    659:        for (int i = 0, end = sub.sbitOffset.size(); i < end; i++) {
                    660:                uint32 offset = sub.sbitOffset[i];
                    661:                uint gid = sub.firstGlyphIndex + i;
                    662: 
                    663:                file.Seek(offset_EBDT + sub.imageDataOffset + offset);
                    664:                BigGlyphMetrics big;
                    665:                big.Load(file);
                    666:                if (debug) {
                    667:                        printf(" %08x %dx%d horiXY=(%d,%d) vertXY=(%d,%d) Adv=%dx%d\n",
                    668:                                offset,
                    669:                                big.width, big.height,
                    670:                                big.horiBearingX,
                    671:                                big.horiBearingY,
                    672:                                big.vertBearingX,
                    673:                                big.vertBearingY,
                    674:                                big.horiAdvance,
                    675:                                big.vertAdvance);
                    676:                }
                    677: 
                    678:                // 64x64 ドットの領域を用意して一旦左上詰めで imageData[] を読み込む。
                    679:                std::vector<uint64> map;
                    680:                int bytelen = HOWMANY(big.width * big.height, 8);
                    681:                int width = big.width;
                    682:                uint64 input = 0;
                    683:                int nbit = 0;
                    684:                for (int j = 0; j < bytelen; j++) {
                    685:                        // 入力キューに下から詰めていく
                    686:                        input = (input << 8) | file.Read8();
                    687:                        nbit += 8;
                    688:                        // 1ライン分を超えてる間切り出す
                    689:                        while (nbit >= width) {
                    690:                                uint64 bytedata;
                    691:                                // 1ライン分を右詰めして..
                    692:                                bytedata = input >> (nbit - width);
                    693:                                // MSB 詰めし直して..
                    694:                                bytedata <<= (64 - width);
                    695:                                // そのまま map の MSB 詰め
                    696:                                map.push_back(bytedata);
                    697:                                // 取り出した分を除外
                    698:                                input <<= 64 - (nbit - width);
                    699:                                input >>= 64 - (nbit - width);
                    700:                                nbit -= width;
                    701:                        }
                    702:                }
                    703: 
                    704:                // X方向へオフセット。
                    705:                // HORIZONTAL_METRICS では horiBearingX は左に入れるパディング。
                    706:                for (auto& m : map) {
                    707:                        m >>= big.horiBearingX;
                    708:                }
                    709:                // Y方向へオフセット。
                    710:                // HORIZONTAL_METRICS では horiBearingY は基準線からグリフ片の
                    711:                // 上端までの上方向へのオフセット。基準線は ascent, descent のやつ。
                    712:                int paddingY = big.vertAdvance - 2 - big.horiBearingY;
                    713:                for (int j = 0; j < paddingY; j++) {
                    714:                        map.insert(map.begin(), 0);
                    715:                }
                    716:                // 縦が足りない分はここで補充
                    717:                map.resize(big.vertAdvance);
                    718: 
                    719:                // horiAdvance * vertAdvance ビット分を書き出す。
                    720:                std::vector<uint8> data;
                    721:                for (int y = 0; y < big.vertAdvance; y++) {
                    722:                        for (int x = 0; x < big.horiAdvance; x += 8) {
                    723:                                uint8 c = map[y] >> (56 - x);
                    724:                                data.push_back(c);
                    725:                        }
                    726:                }
                    727: 
                    728:                if (0 && debug) {
                    729:                        printf("gid=%d\n", gid);
                    730:                        printf("%s\n", DebugBitmapData(big.horiAdvance, data).c_str());
                    731:                }
                    732: 
                    733:                glyph[gid] = data;
                    734:        }
                    735: }
                    736: 
                    737: // indexFormat=2, imageFormat=5
                    738: void
                    739: TTFFile::LoadGlyphFormat2_5(const IndexSubTable& sub)
                    740: {
                    741:        // indexFormat==2 "All glyphs have identical metrics" は
                    742:        //  uint32 imageSize;
                    743:        //  BigGlyphMetrics bigMetrics;
                    744:        // を持っており、ここでメトリックが指定されている。
                    745:        // EBDT 内のオフセットは imageDataOffset。
                    746:        //
                    747:        // imageFormat==5 "metrics in EBLC, bit-aligned image data only" は、
                    748:        // データをビット境界で詰め込んであるのでここでバイト境界にする
                    749:        // (横 12bit を横 2バイトにする)。
                    750: 
                    751:        int nglyph = sub.lastGlyphIndex - sub.firstGlyphIndex + 1;
                    752:        uint32 bytes  = sub.imageSize;
                    753:        file.Seek(offset_EBDT + sub.imageDataOffset);
                    754:        for (int i = 0; i < nglyph; i++) {
                    755:                uint32 gid = sub.firstGlyphIndex + i;
                    756: 
                    757:                std::vector<uint8> data;
                    758:                int width = sub.bigMetrics.width;       // ショートカット
                    759:                uint64 input = 0;                                       // とりあえず横64まで
                    760:                int nbit = 0;                                           // input 内の有効ビット
                    761:                for (int j = 0; j < bytes; j++) {
                    762:                        // 入力キューに下から詰めていく
                    763:                        input = (input << 8) | file.Read8();
                    764:                        nbit += 8;
                    765:                        // 1ライン分を超えたら切り出す
                    766:                        if (nbit >= width) {
                    767:                                uint32 bytedata;
                    768:                                // 1ライン分を右詰めして..
                    769:                                bytedata = input >> (nbit - width);
                    770:                                // MSB 詰めし直して..
                    771:                                bytedata <<= (32 - width);
                    772:                                // 上から1バイトずつ取り出す
                    773:                                for (int k = 0; k < width; k += 8) {
                    774:                                        data.push_back(bytedata >> 24);
                    775:                                        bytedata <<= 8;
                    776:                                }
                    777:                                // 取り出した部分を除外
                    778:                                input <<= 64 - (nbit - width);
                    779:                                input >>= 64 - (nbit - width);
                    780:                                nbit -= width;
                    781:                        }
                    782:                }
                    783:                glyph[gid] = data;
                    784: 
                    785:                if (0 && debug) {
                    786:                        printf("gid=%d\n", gid);
                    787:                        printf("%s\n", DebugBitmapData(width, data).c_str());
                    788:                }
                    789:        }
                    790: }
                    791: 
                    792: // デバッグ用のビットマップデータの表示文字列を返す。
                    793: // widthbit はフォントの横幅(ビット)。
                    794: // data は byte-aligned のデータ。
                    795: std::string
                    796: TTFFile::DebugBitmapData(int widthbit, const std::vector<uint8>& data)
                    797: {
                    798:        std::string str;
                    799: 
                    800:        int wbyte = HOWMANY(widthbit, 8);
                    801:        std::vector<char> buf(widthbit + 2);
                    802: 
                    803:        for (int i = 0, end = data.size(); i < end; i += wbyte) {
                    804:                uint32 v = 0;
                    805:                for (int j = 0; j < wbyte; j++) {
                    806:                        v = (v << 8) | data[i + j];
                    807:                }
                    808:                v <<= (32 - wbyte * 8);
                    809:                int b;
                    810:                for (b = 0; b < wbyte * 8; b++, v <<= 1) {
                    811:                        buf[b] = ((int32)v < 0) ? '@' : '.';
                    812:                }
                    813:                buf[b++] = '\n';
                    814:                buf[b] = '\0';
                    815: 
                    816:                str += std::string(buf.data());
                    817:        }
                    818:        return str;
                    819: }
                    820: 
                    821: // ASCII 部分 (というか半角部分) を BDF で保存する。
                    822: void
                    823: TTFFile::SaveBDFAscii(File& outfile)
                    824: {
                    825:        // ヘッダ出力
                    826:        WriteBDFHeader(outfile, 1);
                    827: 
                    828:        // ここからグリフ出力。
                    829:        // 先に要素数を出力する必要があるので一旦集める。
                    830:        std::vector<std::string> glypharray;
                    831:        for (int code = 0, end = asciimap.size(); code < end; code++) {
                    832:                int gid = asciimap[code];
                    833:                if (gid != 0) {
                    834:                        auto line = MakeChar(code, fontsize / 2, fontsize, glyph[gid]);
                    835:                        glypharray.push_back(line);
                    836:                }
                    837:        }
                    838: 
                    839:        // 出力
                    840:        outfile.Print("CHARS %d\n", (int)glypharray.size());
                    841:        outfile.Write("\n");
                    842:        for (const auto& line : glypharray) {
                    843:                outfile.Write(line.c_str());
                    844:        }
                    845:        outfile.Write("ENDFONT\n");
                    846: }
                    847: 
                    848: // 全角部分を BDF で保存する。
                    849: void
                    850: TTFFile::SaveBDFKanji(File& outfile)
                    851: {
                    852:        // ヘッダ出力
                    853:        WriteBDFHeader(outfile, 2);
                    854: 
                    855:        // ここからグリフ出力。
                    856:        // 先に要素数を出力する必要があるので一旦集める。
                    857:        std::vector<std::string> glypharray;
                    858:        for (int h = 0; h < 0x5e; h++) {
                    859:                for (int l = 0; l < 0x5e; l++) {
                    860:                        int idx = h * 0x5e + l;
                    861:                        int gid = jismap[idx];
                    862:                        int jh = 0x21 + h;
                    863:                        int jl = 0x21 + l;
                    864:                        int jiscode = (jh << 8) + jl;
                    865:                        if (gid != 0) {
                    866:                                auto line = MakeChar(jiscode, fontsize, fontsize, glyph[gid]);
                    867:                                glypharray.push_back(line);
                    868:                        }
                    869:                }
                    870:        }
                    871: 
                    872:        // 出力
                    873:        outfile.Print("CHARS %d\n", (int)glypharray.size());
                    874:        outfile.Write("\n");
                    875:        for (const auto& line : glypharray) {
                    876:                outfile.Write(line.c_str());
                    877:        }
                    878:        outfile.Write("ENDFONT\n");
                    879: }
                    880: 
                    881: // width は 1 なら半角、2 なら全角。
                    882: void
                    883: TTFFile::WriteBDFHeader(File& outfile, int width)
                    884: {
                    885:        // よく分からん
                    886:        std::string foundry = name->GetName(NameID::ManufacturerName);
                    887:        std::string family_name = name->GetName(NameID::PostScriptName);
                    888:        std::string weight = name->GetName(NameID::FontSubfamilyName);
                    889:        const char *slant = "R";
                    890:        const char *setwidth = "Normal";
                    891:        const char *addstyle = "";
                    892:        int pixelsize = fontsize;
                    893:        int pointsize = 150;
                    894:        int resolutionX = 75;
                    895:        int resolutionY = 75;
                    896:        char spacing = 'C';
                    897:        int average_width = fontsize * 10;      // ?
                    898:        const char *charset_registry;
                    899:        if (width == 1) {
                    900:                charset_registry = "ASCII";
                    901:        } else {
                    902:                charset_registry = "JISX0208.1983";
                    903:        }
                    904:        const char *charset_encoding = "0";
                    905: 
                    906:        if (foundry.empty()) {
                    907:                foundry = "misc";
                    908:        }
                    909: 
                    910:        // SIL OFL は改変フォントに元フォントと同じ名前を使ってはいけない。
                    911:        // TTF -> BDF の形式変更も改変になるようにも読めるので、別の名前を使う。
                    912:        if (new_family_name) {
                    913:                family_name = new_family_name;
                    914:        }
                    915: 
                    916:        outfile.Write("STARTFONT 2.1\n");
                    917:        outfile.Print("FONT -%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%c-%d-%s-%s\n",
                    918:                foundry.c_str(),
                    919:                family_name.c_str(),
                    920:                weight.c_str(),
                    921:                slant,
                    922:                setwidth,
                    923:                addstyle,
                    924:                pixelsize,
                    925:                pointsize,
                    926:                resolutionX,
                    927:                resolutionY,
                    928:                spacing,
                    929:                average_width,
                    930:                charset_registry,
                    931:                charset_encoding);
                    932:        outfile.Print("SIZE %d %d %d\n", fontsize, resolutionX, resolutionY);
                    933:        outfile.Print("FONTBOUNDINGBOX %d %d 0 %d\n",
                    934:                fontsize / 2 * width, fontsize, -descent);
                    935:        outfile.Write("\n");
                    936: 
                    937:        // プロパティ。先頭行に要素数を出力する必要があるので一旦集める
                    938:        std::vector<std::string> prop;
                    939: #define PROP(str...)   prop.push_back(string_format(str));
                    940: 
                    941:        PROP("FONTNAME_REGISTRY \"\"");
                    942:        PROP("FOUNDRY \"%s\"", foundry.c_str());
                    943:        PROP("FAMILY_NAME \"%s\"", family_name.c_str());
                    944:        PROP("WEIGHT_NAME \"%s\"", weight.c_str());
                    945:        PROP("SLANT \"%s\"", slant);
                    946:        PROP("SETWIDTH_NAME \"%s\"", setwidth);
                    947:        PROP("ADD_STYLE_NAME \"%s\"", addstyle);
                    948:        PROP("PIXEL_SIZE %d", fontsize);
                    949:        PROP("POINT_SIZE %d", pointsize);
                    950:        PROP("RESOLUTION_X %d", resolutionX);
                    951:        PROP("RESOLUTION_Y %d", resolutionY);
                    952:        PROP("SPACING \"%c\"", spacing);
                    953:        PROP("AVERAGE_WIDTH %d", average_width);
                    954:        PROP("CHARSET_REGISTRY \"%s\"", charset_registry);
                    955:        PROP("CHARSET_ENCODING \"%s\"", charset_encoding);
                    956:        PROP("COPYRIGHT \"%s License: %s %s\"",
                    957:                name->GetName(NameID::Copyright).c_str(),
                    958:                name->GetName(NameID::LicenseDescription).c_str(),
                    959:                name->GetName(NameID::LicenseInfoURL).c_str());
                    960:        PROP("WEIGHT 10");
                    961:        PROP("DEFAULT_CHAR 0"); // ?
                    962:        PROP("FONT_ASCENT %d", ascent);
                    963:        PROP("FONT_DESCENT %d", descent);
                    964: 
                    965:        // 勝手に追加。
                    966:        std::string v;
                    967:        v = name->GetName(NameID::FullFontName);
                    968:        if (v.empty() == false) {
                    969:                PROP("_COMMENT_TTF_FULL_FONT_NAME \"%s\"", v.c_str());
                    970:        }
                    971:        v = name->GetName(NameID::VersionString);
                    972:        if (v.empty() == false) {
                    973:                PROP("_COMMENT_TTF_VERSION \"%s\"", v.c_str());
                    974:        }
                    975:        v = name->GetName(NameID::Designer);
                    976:        if (v.empty() == false) {
                    977:                PROP("_COMMENT_TTF_DESIGNER \"%s\"", v.c_str());
                    978:        }
                    979:        v = name->GetName(NameID::URLVendor);
                    980:        if (v.empty() == false) {
                    981:                PROP("_COMMENT_TTF_URL_VENDOR \"%s\"", v.c_str());
                    982:        }
                    983:        v = name->GetName(NameID::URLDesigner);
                    984:        if (v.empty() == false) {
                    985:                PROP("_COMMENT_TTF_URL_DESIGNER \"%s\"", v.c_str());
                    986:        }
                    987: 
                    988:        outfile.Print("STARTPROPERTIES %d\n", (int)prop.size());
                    989:        for (const auto& s : prop) {
                    990:                outfile.Write(s + "\n");
                    991:        }
                    992:        outfile.Write("ENDPROPERTIES\n");
                    993:        outfile.Write("\n");
                    994: }
                    995: 
                    996: // 1文字分の STARTCHAR .. ENDCHAR までを文字列にしたものを返す。
                    997: std::string
                    998: TTFFile::MakeChar(uint code, int w, int h, const std::vector<uint8>& data)
                    999: {
                   1000:        std::string lines;
                   1001: 
                   1002:        // STARTCHAR のほうはほぼコメント。ENCODING のほうが文字のコード。
                   1003:        if (code < 0x100) {
                   1004:                lines += string_format("STARTCHAR %02x\n", code);
                   1005:        } else {
                   1006:                lines += string_format("STARTCHAR %04x\n", code);
                   1007:        }
                   1008:        lines += string_format("ENCODING %d\n", code);
                   1009:        lines += "SWIDTH 960 0\n";
                   1010:        lines += string_format("DWIDTH %d 0\n", w);
                   1011:        lines += string_format("BBX %d %d 0 %d\n", w, h, -descent);
                   1012:        lines += "BITMAP\n";
                   1013:        // 読み込んだグリフデータは左端を必ずバイト境界から始めてある。
                   1014:        int widthbytes = data.size() / h;
                   1015:        for (int y = 0, yend = data.size(); y < yend; y += widthbytes) {
                   1016:                for (int x = 0; x < widthbytes; x++) {
                   1017:                        lines += string_format("%02x", data[y + x]);
                   1018:                }
                   1019:                lines += "\n";
                   1020:        }
                   1021:        lines += "ENDCHAR\n";
                   1022:        lines += "\n";
                   1023: 
                   1024:        return lines;
                   1025: }
                   1026: 
                   1027: 
                   1028: //
                   1029: // name セクション
                   1030: //
                   1031: 
                   1032: // コンストラクタ
                   1033: TTF_name::TTF_name(File& file, off_t offset_name)
                   1034: {
                   1035:        file.Seek(offset_name);
                   1036:        uint32 version = file.Read16();
                   1037:        uint32 count = file.Read16();
                   1038:        uint32 storageOffset = file.Read16();
                   1039: 
                   1040:        nameRecord.resize(count);
                   1041:        for (int i = 0; i < count; i++) {
                   1042:                auto& rec = nameRecord[i];
                   1043:                rec.platformID = file.Read16();
                   1044:                rec.encodingID = file.Read16();
                   1045:                rec.languageID = file.Read16();
                   1046:                rec.nameID     = file.Read16();
                   1047:                rec.length    = file.Read16();
                   1048:                rec.stringOffset = file.Read16();
                   1049:        }
                   1050:        for (auto& rec : nameRecord) {
                   1051:                file.Seek(offset_name + storageOffset + rec.stringOffset);
                   1052:                if (rec.platformID == Platform_Windows) {
                   1053:                        // UTF-16BE エンコーディングと規定されている
                   1054:                        std::vector<uint8> src(rec.length);
                   1055:                        for (int j = 0; j < rec.length; j++) {
                   1056:                                src[j] = file.Read8();
                   1057:                        }
                   1058:                        rec.name = FromUTF16("utf-16be", src);
                   1059:                } else {
                   1060:                        // とりあえず ASCII だと思ってそのまま使う
                   1061:                        for (int j = 0; j < rec.length; j++) {
                   1062:                                rec.name += (char)file.Read8();
                   1063:                        }
                   1064:                }
                   1065:        }
                   1066: 
                   1067:        if (debug) {
                   1068:                for (int i = 0, end = nameRecord.size(); i < end; i++) {
                   1069:                        const auto& rec = nameRecord[i];
                   1070:                        printf("nameRecord[%d].platformID = %d(%s)\n",
                   1071:                                i, rec.platformID, GetPlatformIDStr(rec.platformID).c_str());
                   1072:                        printf("nameRecord[%d].encodingID = %d\n", i, rec.encodingID);
                   1073:                        printf("nameRecord[%d].languageID = %d\n", i, rec.languageID);
                   1074:                        printf("nameRecord[%d].nameID = %d(%s)\n", i, rec.nameID,
                   1075:                                rec.GetNameIDStr().c_str());
                   1076:                        printf("nameRecord[%d].name = \"%s\"\n", i, rec.name.c_str());
                   1077:                }
                   1078:        }
                   1079:        (void)version;
                   1080:        (void)storageOffset;
                   1081: }
                   1082: 
                   1083: // 指定の文字列を返す。
                   1084: // とりあえず ASCII だけっぽい Macintosh のほうから返す。どうしたもんか。
                   1085: std::string
                   1086: TTF_name::GetName(NameID id) const
                   1087: {
                   1088:        for (const auto& rec : nameRecord) {
                   1089:                if (rec.platformID == Platform_Macintosh && rec.nameID == id) {
                   1090:                        return rec.name;
                   1091:                }
                   1092:        }
                   1093:        return "";
                   1094: }
                   1095: 
                   1096: // デバッグ用に platformID を文字列にして返す
                   1097: /*static*/ std::string
                   1098: TTF_name::GetPlatformIDStr(uint id)
                   1099: {
                   1100:        static const char * const platform_names[] = {
                   1101:                "Unicode",
                   1102:                "Macintosh",
                   1103:                "",
                   1104:                "Windows",
                   1105:        };
                   1106: 
                   1107:        if (id < countof(platform_names)) {
                   1108:                return platform_names[id];
                   1109:        } else {
                   1110:                return "";
                   1111:        }
                   1112: }
                   1113: 
                   1114: 
                   1115: //
                   1116: // EBLC セクション
                   1117: //
                   1118: 
                   1119: // コンストラクタ
                   1120: TTF_EBLC::TTF_EBLC(const File& file_, off_t offset_EBLC)
                   1121:        : file(file_)
                   1122: {
                   1123:        startGlyphIndex = 0;
                   1124:        endGlyphIndex = 65536;
                   1125: 
                   1126:        // EBLC ヘッダ
                   1127:        //  uint16 majorVersion;
                   1128:        //  uint16 minorVersion;
                   1129:        //  uint32 numSizes;
                   1130:        //  BitmapSize bitmapSizes[];
                   1131:        // numSizes フィールドの次から、BitmapSize が numSizes 個並んでるっぽい。
                   1132: 
                   1133:        file.Seek(offset_EBLC);
                   1134:        auto majorVersion = file.Read16();
                   1135:        auto minorVersion = file.Read16();
                   1136:        if (majorVersion != 2 || minorVersion != 0) {
                   1137:                errx(1, "Unknown EBLC version %d.%d", majorVersion, minorVersion); 
                   1138:        }
                   1139:        uint32 numSizes = file.Read32();
                   1140:        if (debug) {
                   1141:                printf("EBLC.numSizes=%d\n", numSizes);
                   1142:        }
                   1143: 
                   1144:        // bitmapSizes[] を全部読み込む
                   1145:        bitmapSizes.resize(numSizes);
                   1146:        for (int i = 0; i < numSizes; i++) {
                   1147:                auto& bs = bitmapSizes[i];
                   1148:                bs.indexSubTableArrayOffset = file.Read32();
                   1149:                bs.indexTablesSize = file.Read32();
                   1150:                bs.numberOfIndexSubTables = file.Read32();
                   1151:                bs.colorRef = file.Read32();
                   1152:                bs.hori.Load(file);
                   1153:                bs.vert.Load(file);
                   1154:                bs.startGlyphIndex = file.Read16();
                   1155:                bs.endGlyphIndex = file.Read16();
                   1156:                bs.ppemX = file.Read8();
                   1157:                bs.ppemY = file.Read8();
                   1158:                bs.bitDepth = file.Read8();
                   1159:                bs.flags = file.Read8();
                   1160:                if (debug) {
                   1161:                        printf("bitmapSizes[%d]\n", i);
                   1162: #define A(fmt, name)   printf(" %-24s = " #fmt "\n", #name, bs.name)
                   1163:                        A($%08x, indexSubTableArrayOffset);
                   1164:                        A($%08x, indexTablesSize);
                   1165:                        A(%d, numberOfIndexSubTables);
                   1166:                        A(%d, colorRef);
                   1167:                        A(%d, startGlyphIndex);
                   1168:                        A(%d, endGlyphIndex);
                   1169:                        A(%d, ppemX);
                   1170:                        A(%d, ppemY);
                   1171:                        A(%d, bitDepth);
                   1172:                        A($%x, flags);
                   1173: 
                   1174:                        if (bs.flags == BitmapSize::HORIZONTAL_METRICS) {
                   1175:                                A(%d, hori.ascender);
                   1176:                                A(%d, hori.descender);
                   1177:                        }
                   1178:                }
                   1179:                if (bs.flags != BitmapSize::HORIZONTAL_METRICS) {
                   1180:                        errx(1, "Unsupported bitmap flags $%x", bs.flags);
                   1181:                }
                   1182: 
                   1183:                // bitmapSizes[] 全体に渡る start..end
                   1184:                startGlyphIndex = std::max(startGlyphIndex, (uint)bs.startGlyphIndex);
                   1185:                endGlyphIndex   = std::min(endGlyphIndex,   (uint)bs.endGlyphIndex);
                   1186: 
                   1187:                // 代表値みたいなのは本当はないかもだが、必要なのでとりあえず。
                   1188:                if (fontsize == 0) {
                   1189:                        fontsize = bs.ppemY;
                   1190:                } else if (fontsize != bs.ppemY) {
                   1191:                        errx(1, "bs.ppemY=%d but already has %d", bs.ppemY, fontsize);
                   1192:                }
                   1193:                if (ascent == 0) {
                   1194:                        ascent = bs.hori.ascender;
                   1195:                } else if (ascent != bs.hori.ascender) {
                   1196:                        errx(1, "bs.hori.ascender=%d but already has %d",
                   1197:                                bs.hori.ascender, ascent);
                   1198:                }
                   1199:                // (TTF の) descender は負数、(BDF の) descent は正数ということにする。
                   1200:                if (descent == 0) {
                   1201:                        descent = -bs.hori.descender;
                   1202:                } else if (descent != bs.hori.descender) {
                   1203:                        errx(1, "bs.hori.descender=%d but already has (-)%d",
                   1204:                                bs.hori.descender, descent);
                   1205:                }
                   1206:        }
                   1207: 
                   1208:        // 各 bitmapSizes には indexSubTables[] 配列がある。
                   1209:        for (auto& bs : bitmapSizes) {
                   1210:                bs.indexSubTable.resize(bs.numberOfIndexSubTables);
                   1211: 
                   1212:                // indexSubTableArrayOffset は EBLC 先頭からのオフセット。
                   1213:                // indexSubTable[] 自体にはグリフ範囲と additional へのオフセットのみ
                   1214:                // 記録されている。additional のほうはフォーマットによってサイズが
                   1215:                // 異なるためだと思う。
                   1216:                // additional が指す先は indexSubHeader で、ここの indexFormat で
                   1217:                // この後に続く indexSubTable の種別が決まっている。
                   1218:                //
                   1219:                // indexSubTable {
                   1220:                //   { firstGlyphIndex, lastGlyphIndex }
                   1221:                //   additionalOffsetToIndexSubTable ----+
                   1222:                // }                                     |
                   1223:                //                                       |
                   1224:                // +-------------------------------------+
                   1225:                // |
                   1226:                // +-> indexSubHeader {
                   1227:                //   indexFormat = 1;
                   1228:                //   imageFormat;
                   1229:                //   imageDataOffset --> EBDT 内のオフセット
                   1230:                // }
                   1231:                // indexSubTable1 {
                   1232:                //   IndexSubType;
                   1233:                //   sbitOffset[];
                   1234:                // }
                   1235:                // 
                   1236:                file.Seek(offset_EBLC + bs.indexSubTableArrayOffset);
                   1237:                for (int j = 0; j < bs.numberOfIndexSubTables; j++) {
                   1238:                        auto& sub = bs.indexSubTable[j];
                   1239:                        sub.firstGlyphIndex = file.Read16();
                   1240:                        sub.lastGlyphIndex  = file.Read16();
                   1241:                        sub.additionalOffsetToIndexSubTable = file.Read32();
                   1242:                        if (debug) {
                   1243:                                printf("indexSubTable[%d] GlyphIndex=%4d-%4d "
                   1244:                                        "additionalOffsetToIndexSubTable=$%08x\n", j,
                   1245:                                        sub.firstGlyphIndex,
                   1246:                                        sub.lastGlyphIndex,
                   1247:                                        sub.additionalOffsetToIndexSubTable);
                   1248:                        }
                   1249:                }
                   1250: 
                   1251:                for (int j = 0; j < bs.numberOfIndexSubTables; j++) {
                   1252:                        auto& sub = bs.indexSubTable[j];
                   1253:                        file.Seek(offset_EBLC
                   1254:                                + bs.indexSubTableArrayOffset
                   1255:                                + sub.additionalOffsetToIndexSubTable);
                   1256:                        // ここが indexSubType header
                   1257:                        sub.indexFormat = file.Read16();
                   1258:                        sub.imageFormat = file.Read16();
                   1259:                        sub.imageDataOffset = file.Read32();
                   1260:                        if (debug) {
                   1261:                                printf("[%d] indexFormat=%d imageFormat=%d "
                   1262:                                        "imageDataOffset=$%08x\n",
                   1263:                                        j, sub.indexFormat, sub.imageFormat, sub.imageDataOffset);
                   1264:                        }
                   1265: 
                   1266:                        switch (sub.indexFormat) {
                   1267:                         case 1:        // indexSubTable1
                   1268:                         {
                   1269:                                // IndexSubType header;
                   1270:                                // Offset32     sbitOffset[];
                   1271:                                //
                   1272:                                // 公式ドキュメントの改行位置が微妙に分からんけど。
                   1273:                                //  sbitOffsets[glyphIndex] + imageDataOffset = glyphData;
                   1274:                                //  sizeOfArray = (lastGlyph - firstGlyph + 1) + 1
                   1275:                                //                + 1 pad if needed;
                   1276:                                int nglyph = sub.lastGlyphIndex - sub.firstGlyphIndex + 1;
                   1277:                                sub.sbitOffset.resize(nglyph);
                   1278:                                for (int i = 0; i < nglyph; i++) {
                   1279:                                        uint32 offset = file.Read32();
                   1280:                                        sub.sbitOffset[i] = offset;
                   1281:                                        if (debug) {
                   1282:                                                printf(" %08x", offset);
                   1283:                                                if (i % 8 == 7) {
                   1284:                                                        printf("\n");
                   1285:                                                }
                   1286:                                        }
                   1287:                                }
                   1288:                                if (debug) {
                   1289:                                        printf("\n");
                   1290:                                }
                   1291:                                break;
                   1292:                         }
                   1293: 
                   1294:                         case 2:        // indexSubTable2
                   1295:                         {
                   1296:                                // IndexSubType    header;
                   1297:                                // uint32          imageSize;
                   1298:                                // BigGlyphMetrics bigMetrics;
                   1299:                                sub.imageSize = file.Read32();
                   1300:                                auto& big = sub.bigMetrics;
                   1301:                                big.Load(file);
                   1302:                                if (debug) {
                   1303:                                        printf(" imageSize=%d bigMetrics=%dx%d\n",
                   1304:                                                sub.imageSize, big.width, big.height);
                   1305:                                }
                   1306:                                break;
                   1307:                         }
                   1308: 
                   1309:                         default:
                   1310:                                errx(1, "unsupported indexSubTable%d", sub.indexFormat);
                   1311:                        }
                   1312:                }
                   1313:        }
                   1314: }
                   1315: 
                   1316: 
                   1317: //
                   1318: // cmap セクション
                   1319: //
                   1320: 
                   1321: // コンストラクタ
                   1322: TTF_cmap::TTF_cmap(const File& file_, off_t offset)
                   1323:        : file(file_)
                   1324: {
                   1325:        // cmap ヘッダ
                   1326:        //
                   1327:        //  uint16 version;             // Table version number (0).
                   1328:        //  uint16 numTables;   // Number of encoding tables that follow.
                   1329:        //  EncodingRecord encodingRecords[numTables];
                   1330: 
                   1331:        file.Seek(offset);
                   1332:        uint16 version = file.Read16();
                   1333:        uint16 numTables = file.Read16();
                   1334: 
                   1335:        if (version != 0) {
                   1336:                errx(1, "Unsupported cmap version %d\n", version);
                   1337:        }
                   1338: 
                   1339:        printf("cmap:\n");
                   1340:        encodingRecords.resize(numTables);
                   1341:        for (int i = 0; i < encodingRecords.size(); i++) {
                   1342:                auto& enc = encodingRecords[i];
                   1343:                enc.platformID = file.Read16();
                   1344:                enc.encodingID = file.Read16();
                   1345:                enc.subtableOffset = file.Read32();
                   1346: 
                   1347:                if (debug) {
                   1348:                        printf("[%d] %s subtableOffset=%08x\n", i,
                   1349:                                enc.ToString().c_str(),
                   1350:                                enc.subtableOffset);
                   1351:                }
                   1352:        }
                   1353: 
                   1354:        // とりあえず Unicode2.0 BMP のみターゲットにする。
                   1355:        EncodingRecord *uenc = NULL;
                   1356:        for (auto& enc : encodingRecords) {
                   1357:                if (enc.platformID == 0 && enc.encodingID == 3) {
                   1358:                        uenc = &enc;
                   1359:                }
                   1360:        }
                   1361:        if (uenc == NULL) {
                   1362:                errx(1, "cmap: Unicode2.0 BMP mapping not found");
                   1363:        }
                   1364: 
                   1365:        // Unicode2.0 BMP の場合 offset の先は Format4 らしい。
                   1366:        // subtableOffset は cmap 先頭からのオフセット。
                   1367:        off_t tablestart = file.Seek(offset + uenc->subtableOffset);
                   1368:        sub.format = file.Read16();
                   1369:        sub.length = file.Read16();
                   1370:        sub.language = file.Read16();
                   1371:        sub.segCountX2 = file.Read16();
                   1372:        sub.searchRange = file.Read16();
                   1373:        sub.entrySelector = file.Read16();
                   1374:        sub.rangeShift = file.Read16();
                   1375: 
                   1376:        int segCount = sub.segCountX2 / 2;
                   1377:        sub.endCode.resize(segCount);
                   1378:        sub.startCode.resize(segCount);
                   1379:        sub.idDelta.resize(segCount);
                   1380:        sub.idRangeOffsets.resize(segCount);
                   1381: 
                   1382:        for (int i = 0; i < segCount; i++) {
                   1383:                sub.endCode[i] = file.Read16();
                   1384:        }
                   1385:        file.Read16();  // reservedPad
                   1386:        for (int i = 0; i < segCount; i++) {
                   1387:                sub.startCode[i] = file.Read16();
                   1388:        }
                   1389:        for (int i = 0; i < segCount; i++) {
                   1390:                sub.idDelta[i] = file.Read16();
                   1391:        }
                   1392:        for (int i = 0; i < segCount; i++) {
                   1393:                sub.idRangeOffsets[i] = file.Read16();
                   1394:        }
                   1395:        // glyphIdArray[] の長さは直接は書いてないが、sub.length が
                   1396:        // (たぶん subtable 先頭からの) subtable のバイト長らしいので、そこまで。
                   1397:        int remain = sub.length - (file.Tell() - tablestart);
                   1398:        sub.glyphIdArray.resize(remain / 2);
                   1399:        for (int i = 0; i < remain / 2; i++) {
                   1400:                sub.glyphIdArray[i] = file.Read16();
                   1401:        }
                   1402: 
                   1403:        if (debug) {
                   1404:                printf("cmap SubTable Format4\n");
                   1405:                printf(" format=%d\n", sub.format);
                   1406:                printf(" length=%d\n", sub.length);
                   1407:                printf(" language=%d\n", sub.language);
                   1408:                printf(" segCountX2=%d\n", sub.segCountX2);
                   1409:                printf(" searchRange=%d\n", sub.searchRange);
                   1410:                printf(" entrySelector=%d\n", sub.entrySelector);
                   1411:                printf(" rangeShift=%d\n", sub.rangeShift);
                   1412:                printf(" glyphIdArray[%d]\n", (int)sub.glyphIdArray.size());
                   1413:        }
                   1414: }
                   1415: 
                   1416: // ASCII というか1バイトコードのマップを作成する。
                   1417: // asciimap は 0-255 確保されていること。
                   1418: void
                   1419: TTF_cmap::MakeASCIIMap(std::vector<uint>& asciimap)
                   1420: {
                   1421:        // ASCII + 1バイトコード
                   1422:        for (int code = 1, end = asciimap.size(); code < end; code++) {
                   1423:                asciimap[code] = Code2GID(code);
                   1424:        }
                   1425:        if (debug) {
                   1426:                printf("asciimap:\n");
                   1427:                for (int i = 0, end = asciimap.size(); i < end; i++) {
                   1428:                        printf(" %3d", asciimap[i]);
                   1429:                        if (i % 16 == 15) {
                   1430:                                printf("\n");
                   1431:                        }
                   1432:                }
                   1433:        }
                   1434: }
                   1435: 
                   1436: // JIS コードのマップを作成する。
                   1437: // jismap はあらかじめ確保されていること。
                   1438: void
                   1439: TTF_cmap::MakeJISMap(std::vector<uint>& jismap)
                   1440: {
                   1441:        auto cd = iconv_open("unicodebig", "iso-2022-jp");
                   1442:        if (cd == (iconv_t)-1) {
                   1443:                err(1, "iconv_open");
                   1444:        }
                   1445: 
                   1446:        for (int h = 0; h < 0x5e; h++) {
                   1447:                for (int l = 0; l < 0x5e; l++) {
                   1448:                        int idx = h * 0x5e + l;
                   1449: 
                   1450:                        // JIS コードを Unicode コードポイントに変換
                   1451:                        int jh = 0x21 + h;
                   1452:                        int jl = 0x21 + l;
                   1453:                        std::string srcbuf = string_format("\x1b$B%c%c\x1b(B", jh, jl);
                   1454:                        const char *src = &srcbuf[0];
                   1455:                        size_t srcleft = srcbuf.length();
                   1456:                        std::array<uint8, 4> dstbuf;
                   1457:                        char *dst = (char *)dstbuf.data();
                   1458:                        size_t dstleft = dstbuf.size();
                   1459:                        auto r = ICONV(cd, &src, &srcleft, &dst, &dstleft);
                   1460:                        if (r == (size_t)-1) {
                   1461:                                // JIS コードの割り当てがないところでは EILSEQ になる
                   1462:                                if (errno == EILSEQ) {
                   1463:                                        continue;
                   1464:                                }
                   1465:                                err(1, "iconv %02x%02x failed", jh, jl);
                   1466:                        }
                   1467:                        if (r != 0) {
                   1468:                                errx(1, "iconv: invalid conversions is %zd", r);
                   1469:                        }
                   1470:                        if (dstleft != 2) {
                   1471:                                errx(1, "iconv %02x%02x: dstleft=%zd", jh, jl, dstleft);
                   1472:                        }
                   1473:                        // UnicodeBig は2バイト。
                   1474:                        // ビッグエンディアンで取り出しているので上位、下位の順
                   1475:                        uint32 ucode = (dstbuf[0] << 8) | dstbuf[1];
                   1476: 
                   1477:                        // JIS コードの {jh,jl} を Unicode に変換して GID を引く。
                   1478:                        auto gid = Code2GID(ucode);
                   1479:                        jismap[idx] = gid;
                   1480:                }
                   1481:        }
                   1482:        iconv_close(cd);
                   1483: 
                   1484:        if (0 && debug) {
                   1485:                printf("jismap:\n");
                   1486:                for (int h = 0; h < 0x5e; h++) {
                   1487:                        for (int l = 0; l < 0x5e; l++) {
                   1488:                                int idx = h * 0x5e + l;
                   1489:                                int gid = jismap[idx];
                   1490:                                if (gid != 0) {
                   1491:                                        printf(" JIS%02x%02x GID=%4d\n", h + 0x21, l + 0x21, gid);
                   1492:                                }
                   1493:                        }
                   1494:                }
                   1495:        }
                   1496: }
                   1497: 
                   1498: // 文字コード code からグリフインデックス(GID)を求める
                   1499: int
                   1500: TTF_cmap::Code2GID(int code) const
                   1501: {
                   1502:        // endCode[] から code を含むセグメント i を求める
                   1503:        int i = -1;
                   1504:        for (int j = 0; j < sub.endCode.size(); j++) {
                   1505:                if (code <= sub.endCode[j]) {
                   1506:                        i = j;
                   1507:                        break;
                   1508:                }
                   1509:        }
                   1510:        if (i < 0) {
                   1511:                return 0;
                   1512:        }
                   1513: 
                   1514:        // このセグメントの開始コードより若ければ、対応インデックスなし
                   1515:        int start = sub.startCode[i];
                   1516:        if (code < start) {
                   1517:                return 0;
                   1518:        }
                   1519: 
                   1520:        if (sub.idRangeOffsets[i] == 0) {
                   1521:                return (code + sub.idDelta[i]) & 0xffff;
                   1522:        } else {
                   1523:                errx(1, "idRangeOffset != 0");
                   1524:        }
                   1525: }
                   1526: 
                   1527: 
                   1528: // BigGlyphMetrics を読み込む。file は更新される。
                   1529: void
                   1530: BigGlyphMetrics::Load(File& file)
                   1531: {
                   1532:        height                  = file.Read8();
                   1533:        width                   = file.Read8();
                   1534:        horiBearingX    = file.Read8();
                   1535:        horiBearingY    = file.Read8();
                   1536:        horiAdvance             = file.Read8();
                   1537:        vertBearingX    = file.Read8();
                   1538:        vertBearingY    = file.Read8();
                   1539:        vertAdvance             = file.Read8();
                   1540: }
                   1541: 
                   1542: // SbitLineMetrics を読み込む。file は更新される。
                   1543: void
                   1544: SbitLineMetrics::Load(File& file)
                   1545: {
                   1546:        ascender                = file.Read8();
                   1547:        descender               = file.Read8();
                   1548:        widthMax                = file.Read8();
                   1549:        caretSlopeNumerator             = file.Read8();
                   1550:        caretSlopeDenominator   = file.Read8();
                   1551:        caretOffset             = file.Read8();
                   1552:        minOriginSB             = file.Read8();
                   1553:        minAdvanceSB    = file.Read8();
                   1554:        maxBeforeBL             = file.Read8();
                   1555:        minAfterBL              = file.Read8();
                   1556:        pad1                    = file.Read8();
                   1557:        pad2                    = file.Read8();
                   1558: }
                   1559: 
                   1560: // NameRecord.NameID の名前を文字列で返す
                   1561: /*static*/ std::string
                   1562: NameRecord::GetNameIDStr(uint id)
                   1563: {
                   1564:        static const char * const names[] = {
                   1565:                "Copyright notice",                             // 0
                   1566:                "Font Family name",                             // 1
                   1567:                "Font Subfamily name",                  // 2
                   1568:                "Unique font identifier",               // 3
                   1569:                "Full font name",                               // 4
                   1570:                "Version string",                               // 5
                   1571:                "PostScript name",                              // 6
                   1572:                "Trademark",                                    // 7
                   1573:                "Manufacturer Name",                    // 8
                   1574:                "Designer",                                             // 9
                   1575:                "Description",                                  // 10
                   1576:                "URL Vendor",                                   // 11
                   1577:                "URL Designer",                                 // 12
                   1578:                "License Description",                  // 13
                   1579:                "License Info",                                 // 14
                   1580:                "Reserved",                                             // 15
                   1581:                "Typographic Family name",              // 16
                   1582:                "Typographic Subfamily name",   // 17
                   1583:                "Compatible Full",                              // 18
                   1584:                "Sample Text",                                  // 19
                   1585:                "PostScript CID findfont name", // 20
                   1586:                "WWS Family Name",                              // 21
                   1587:                "WWS Subfamily Name",                   // 22
                   1588:                "Light Background Palette",             // 23   
                   1589:                "Dark Background Palette",              // 24
                   1590:                "Variations PostScript Name Prefix",    // 25
                   1591:        };
                   1592:        if (id < countof(names)) {
                   1593:                return names[id];
                   1594:        } else {
                   1595:                return "";
                   1596:        }
                   1597: }
                   1598: 
                   1599: // EncodingRecord のデバッグ表示用文字列を返す
                   1600: std::string
                   1601: EncodingRecord::ToString() const
                   1602: {
                   1603:        std::string str;
                   1604: 
                   1605:        str = string_format("platformID=%d", platformID);
                   1606:        static const char * const platform_names[] = {
                   1607:                "Unicode",
                   1608:                "Macintosh",
                   1609:                "ISO(deprecated)",
                   1610:                "Windows",
                   1611:                "Custom",
                   1612:        };
                   1613:        if (platformID < countof(platform_names)) {
                   1614:                str += string_format("(%s)", platform_names[platformID]);
                   1615:        }
                   1616: 
                   1617:        str += string_format(" encodingID=%d", encodingID);
                   1618:        if (platformID == 0) {
                   1619:                static const char * encoding_names_0[] = {
                   1620:                        "1.0",
                   1621:                        "1.1",
                   1622:                        "ISO/IEC 10646",
                   1623:                        "2.0 BMP",
                   1624:                        "2.0 full",
                   1625:                        "Variation Sequences",
                   1626:                        "full reportoire",
                   1627:                };
                   1628:                if (encodingID < countof(encoding_names_0)) {
                   1629:                        str += string_format("(%s)", encoding_names_0[encodingID]);
                   1630:                }
                   1631:        } else if (platformID == 3) {
                   1632:                static const char * encoding_names_3[] = {
                   1633:                        "Symbol",
                   1634:                        "Unicode BMP",
                   1635:                        "ShiftJIS",
                   1636:                        "PRC",
                   1637:                        "Big5",
                   1638:                        "Wansung",
                   1639:                        "Johab",
                   1640:                        "Reserved",
                   1641:                        "Reserved",
                   1642:                        "Reserved",
                   1643:                        "Unicode full reportoire",
                   1644:                };
                   1645:                if (encodingID < countof(encoding_names_3)) {
                   1646:                        str += string_format("(%s)", encoding_names_3[encodingID]);
                   1647:                }
                   1648:        }
                   1649: 
                   1650:        return str;
                   1651: }
                   1652: 
                   1653: 
                   1654: [[noreturn]] static void
                   1655: usage()
                   1656: {
                   1657:        errx(1, "usage: [-f family_name] infile.TTF outascii.BDF outkanji.BDF");
                   1658: }
                   1659: 
                   1660: int
                   1661: main(int ac, char *av[])
                   1662: {
                   1663:        int c;
                   1664: 
                   1665:        while ((c = getopt(ac, av, "f:")) != -1) {
                   1666:                switch (c) {
                   1667:                 case 'f':
                   1668:                        new_family_name = optarg;
                   1669:                        break;
                   1670:                 default:
                   1671:                        usage();
                   1672:                        break;
                   1673:                }
                   1674:        }
                   1675:        ac -= optind;
                   1676:        av += optind;
                   1677: 
                   1678:        if (ac < 3) {
                   1679:                usage();
                   1680:        }
                   1681: 
                   1682:        File infile;
                   1683:        infile.Open(av[0]);
                   1684: 
                   1685:        TTFFile ttf;
                   1686:        ttf.Open(infile);
                   1687: 
                   1688:        File outfile1;
                   1689:        outfile1.Create(av[1]);
                   1690:        ttf.SaveBDFAscii(outfile1);
                   1691: 
                   1692:        File outfile2;
                   1693:        outfile2.Create(av[2]);
                   1694:        ttf.SaveBDFKanji(outfile2);
                   1695: 
                   1696:        return 0;
                   1697: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.