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

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

unix.superglobalmegacorp.com

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