Last active
May 14, 2022 07:08
-
-
Save nomissbowling/ce9307ef94e7e06f9abdfee44eb8aacf to your computer and use it in GitHub Desktop.
testFT.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
testFT.cpp | |
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe" | |
-source-charset:utf-8 -execution-charset:utf-8 | |
-EHsc -FetestFT.exe testFT.cpp | |
-I..\FreeType\include | |
-link | |
/LIBPATH:..\FreeType\x64 | |
/LIBPATH:"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64" | |
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\ucrt\x64" | |
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x64" | |
freetype.lib | |
del .\testFT.obj | |
testFT | |
https://freetype.org/ | |
Unicode Variation Sequences | |
https://freetype.org/freetype2/docs/reference/ft2-glyph_variants.html | |
VS | |
https://hanya-orz.hatenablog.com/entry/20151228/p1 | |
FT_ULong uc = static_cast<FT_ULong>(L'𠮟'); | |
FT_UInt32 | |
FT_Face_GetVariantSelectors | |
FT_Face_GetVariantsOfChar | |
FT_Face_GetCharsOfVariant | |
FT_Face_GetCharVariantIndex | |
https://freetype.org/freetype2/docs/reference/ft2-glyph_variants.html#ft_face_getcharvariantindex | |
surrogate pair | |
https://ja.wikipedia.org/wiki/Unicode | |
u6f23 漣 | |
u82a6 芦 u8606 蘆 | |
u4e80 亀 u9f9c 龜 | |
u7515 甕 | |
u9e7d 鹽 | |
u212b Å u00c5 Å | |
u00ee î | |
u9d0e 鴎 u9dd7 鷗 | |
u53f1 叱 u20b9f 𠮟 | |
Migu 1M: migu-1m-regular.ttf | |
face has e0100 e0101 e0102 Migu 1M | |
000e0100: 000053c9 000054ac 00005efb 0000633a 000065a7 00006756 00006897 | |
0000723a 00007259 000072e1 000082a6 000091dc 00009375 00009771 | |
000097ad 000099c1 00009bab | |
000e0101: 00006f23 | |
000e0102: 00006756 00006f23 00007259 000082a6 | |
L'漣' has e0100 e0101 Migu 1M | |
000e0101: (same) | |
000e0102: (same) | |
L'芦' has e0100 e0102 Migu 1M | |
000e0100: (same) | |
000e0102: (same) | |
https://itouhiro.hatenablog.com/entry/20130419 | |
https://itouhiro.hatenablog.com/entry/20121031 | |
https://itouhiro.hatenablog.com/entry/20120924 | |
https://tasuten.hatenablog.com/entry/20110219/1298050878 | |
https://dtp-bbs.com/forum/archives/n20150327120350_20150327120350.html | |
https://moji-memo.hatenablog.jp/entry/20130408/1365404490 | |
https://www.iwatafont.co.jp/news/img/about_font.pdf | |
VS Variation Selector IVS | |
https://moji.or.jp/mojikiban/aboutivs/ | |
https://ja.wikipedia.org/wiki/%E7%95%B0%E4%BD%93%E5%AD%97%E3%82%BB%E3%83%AC%E3%82%AF%E3%82%BF | |
https://community.dal.co.jp/s/article/kanji-variants | |
http://itdoc.hitachi.co.jp/manuals/3020/30203n7360/NTSO0492.htm | |
http://itdoc.hitachi.co.jp/manuals/3020/30203N73A0/NTSO0554.htm | |
IVS VS17-VS256 ue0100-ue01ef Ideographic Variation Sequence | |
http://www.unicode.org/ivd/ | |
SVS VS1-VS16 ufe00-ufe0f Standardized Variation Sequence | |
http://www.unicode.org/Public/UNIDATA/StandardizedVariants.txt | |
cmap table | |
https://aznote.jakou.com/prog/opentype/08_cmap.html | |
old JIS90 JIS2004 | |
https://fontnavi.jp/zakkuri/304-jis2004_jis90.aspx | |
tag jp90 jp04 | |
https://moji-memo.hatenablog.jp/entry/20080219/1203409203 | |
IPAex IPA font https://moji.or.jp/ipafont/ | |
hanazono font http://fonts.jp/hanazono/ | |
Migu 1M font https://mix-mplus-ipa.osdn.jp/migu/ | |
MigMix 1M font https://mix-mplus-ipa.osdn.jp/migmix/ | |
create composite font https://itouhiro.hatenablog.com/entries/2012/10/31 | |
Migu 1VS (DejaVu Sans Condensed + Migu 1C) | |
Migu 1BT (Bitter + Migu 1C) | |
Migu 2DS (Droid Sans + MigMix 2P) | |
DejaVu Sans Condensed https://dejavu-fonts.github.io/ | |
https://github.com/dejavu-fonts/dejavu-fonts | |
Bitter https://fonts.google.com/specimen/Bitter | |
https://fontmeme.com/jfont/bitter-font/ | |
Droid Sans https://fontmeme.com/jfont/droid-sans-font/ | |
芦󠄀 -> u82a6 ue0100 -> 82 a6 db 40 dd 00 | |
祇󠄀 -> u7947 ue0100 | |
祇󠄁 -> u7947 ue0101 | |
祗 -> u7957 | |
衹 -> u8879 | |
*/ | |
#define UNICODE | |
#define _UNICODE | |
#include <wchar.h> | |
#define _USE_MATH_DEFINES | |
#include <cmath> | |
#include <iomanip> | |
#include <iostream> | |
#include <sstream> | |
#include <map> | |
#include <vector> | |
#include <string> | |
#include <stdexcept> | |
#include <exception> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <freetype/freetype.h> | |
typedef unsigned char uchar; | |
#if 1 | |
#define FONT_BASE "C:\\Windows\\Fonts\\" | |
// #define FONT_FN FONT_BASE"ipaexm.ttf" // OK u9dd7 u20b9f u82a6 (u8879) | |
// #define FONT_FN FONT_BASE"ipaexg.ttf" // OK u9dd7 u20b9f u82a6 (u8879) | |
#define FONT_FN FONT_BASE"migu-1m-regular.ttf" // OK u9dd7 u20b9f (u82a6 u8879) | |
// #define FONT_FN FONT_BASE"migmix-1m-regular.ttf" // BAD IVS (u82a6 u8879) | |
// #define FONT_FN FONT_BASE"msgothic.ttc" // OK u9dd7 u20b9f u82a6 u8879 | |
// #define FONT_FN FONT_BASE"DFLgs9.ttc" // OK but not support some glyph | |
// #define FONT_FN FONT_BASE"DFLgs9.ttf" // font exists but can not get glyph | |
// #define FONT_FN FONT_BASE"consola.ttf" // not support wchar_t area | |
#else | |
#define FONT_BASE ".\\" | |
#define FONT_FN FONT_BASE"mikaP.ttf" | |
#endif | |
using namespace std; | |
inline unsigned int calcW(unsigned int bitsPixel, unsigned int w) | |
{ | |
return ((bitsPixel / 8) * w) & ~3; | |
} | |
FT_Int drawBitmap(FT_GlyphSlot slot) | |
{ | |
FT_Bitmap *bmp = &slot->bitmap; | |
#if 0 | |
FT_Int tw = dst.size().width, th = dst.size().height; | |
#else | |
FT_Int tw = bmp->width, th = bmp->rows; | |
#endif | |
FT_Int mw = calcW(24, tw); | |
#if 0 | |
FT_Int x = loc.x, y = loc.y; // check in loop i<0 j<0 or no wrap left<->right | |
#else | |
FT_Int x = 0, y = 0; | |
#endif | |
#if 0 | |
fprintf(stdout, "(%d %d) %d (%d %d)", tw, th, mw, x, y); | |
fprintf(stdout, " %d %d %d %d %d %d\n", slot->bitmap_left, slot->bitmap_top, | |
slot->bitmap.width, slot->bitmap.rows, slot->advance.x, slot->advance.y); | |
#endif | |
FT_Int x_max = x + bmp->width; // + slot->bitmap_left | |
FT_Int y_max = y + bmp->rows; // - slot->bitmap_top | |
FT_Int i, j, p, q; | |
for(j = y, q = 0; j < y_max; j++, q++){ // j = y - slot->bitmap_top | |
#if 0 | |
uchar *img_line = (uchar *)dst.data + j * mw; | |
#endif | |
for(i = x, p = 0; i < x_max; i++, p++){ // i = x + slot->bitmap_left | |
uchar b = bmp->buffer[q * bmp->width + p]; | |
#if 1 | |
fprintf(stdout, "%c", ".-+*"[b >> 6]); | |
#endif | |
if(i < 0 || j < 0 || i >= tw || j >= th) continue; | |
#if 0 | |
uchar *img = img_line + i * 3; | |
double a = b / 255.0; | |
for(int c = 0; c < 3; ++c){ | |
uchar s = *img; | |
*img++ = (uchar)(a * col[c] + (1.0 - a) * s); | |
} | |
#endif | |
} | |
#if 1 | |
fprintf(stdout, "\n"); | |
#endif | |
} | |
return slot->bitmap.width; // + slot->bitmap_left | |
} | |
int main(int ac, char **av) | |
{ | |
fprintf(stdout, "sizeof(size_t): %zd\n", sizeof(size_t)); | |
FT_Library library; | |
FT_Error error = FT_Init_FreeType(&library); | |
FT_Face face; | |
FT_Int p = 0; // face index 0: proportional, 1: fixed (wide) eg DFLgs9.ttc | |
error = FT_New_Face(library, FONT_FN, p, &face); // FT_New_Memory_Face | |
#if 0 | |
error = FT_Select_Charmap(face, FT_ENCODING_UNICODE); | |
#endif | |
FT_Int dpi = 72, ffact = 64, fpt = 16; // ffact: 64 (1:1) at 72dpi | |
FT_Int scale = (FT_Int)(fpt * 2.0); // fontScale = 2.0 | |
// use 16pt(test) or 48pt(release) at 100dpi (1:1 at 72dpi) | |
error = FT_Set_Char_Size(face, scale * ffact, 0, dpi, 0); | |
#if 0 | |
error = FT_Select_Size(face, fpt); // always 16pt ? returns 35 ? | |
#else | |
error = FT_Set_Pixel_Sizes(face, scale, scale); // width height OK | |
#endif | |
#if 1 // get Selectors (VS) | |
vector<FT_UInt32> vsel; // unknown size | |
#if 1 // vsel for face has e0100 e0101 e0102 Migu 1M | |
FT_UInt32 *fsel = FT_Face_GetVariantSelectors(face); | |
if(fsel) while(*fsel) vsel.push_back(*fsel++); | |
#else // vsel for L'芦' has e0100 e0102 Migu 1M (L'漣' has e0101 e0102) | |
FT_ULong uc = static_cast<FT_ULong>(L'芦'); // L'叱' L'𠮟' has no gsel | |
FT_UInt32 *gsel = FT_Face_GetVariantsOfChar(face, uc); | |
if(gsel) while(*gsel) vsel.push_back(*gsel++); | |
#endif | |
// get CodePoints in each Selectors | |
map<FT_UInt32, vector<FT_UInt32> > vselCodePoints; | |
for(auto &v : vsel){ | |
FT_UInt32 *codePoints = FT_Face_GetCharsOfVariant(face, v); | |
if(codePoints) | |
while(*codePoints) vselCodePoints[v].push_back(*codePoints++); | |
} | |
#if 0 // display Selectors and CodePoints | |
for(auto &kv : vselCodePoints){ | |
fprintf(stderr, " %08x:", kv.first); | |
for(auto &cp : kv.second) fprintf(stderr, " %08x", cp); | |
fprintf(stderr, "\n"); | |
/* | |
for face | |
000e0100: 000053c9 ... 00009bab | |
000e0101: 00006f23 | |
000e0102: 00006756 ... 000082a6 | |
for L'芦' | |
000e0100: 000053c9 ... 00009bab | |
000e0102: 00006756 ... 000082a6 | |
*/ | |
} | |
#endif | |
#endif | |
#if 0 // debug only | |
if(true){ | |
#if 0 | |
FT_ULong uni = L'\u3042'; // u3042 | |
wchar_t u[] = L"\u3042"; // u3042 -> index of mikaP.ttf = 0x07bd | |
*u = L"\u3041"[0]; // re write it (anti optimize) 0x07bc | |
*u = L"\u9b31"[0]; // re write it (anti optimize) 0x3760 | |
#endif | |
FT_ULong wc = 0x20b9f; // not found (0xd842df9f bad wc vs) | |
FT_Int gid = FT_Face_GetCharVariantIndex(face, wc, 0x000e0100); // vs | |
fprintf(stderr, "test VS id: %08x: %08x\a\n", wc, gid); // 0x00000000 | |
wc = 0x20b9f; // found 0x00003153 (0xd842df9f bad wc) | |
if(!gid) gid = FT_Get_Char_Index(face, wc); | |
fprintf(stderr, "test gid id: %08x: %08x\a\n", wc, gid); // 0x00003153 | |
} | |
#endif | |
FT_GlyphSlot slot = face->glyph; | |
#if 0 | |
cv::Point loc = pos; // copy | |
#else | |
int locx = 0; | |
#endif | |
#if 1 | |
#if 0 | |
// 鷗 u9dd7 𠮟 u20b9f = ud842 udf9f 漣 u6f23 芦 u82a6 | |
// const wchar_t *wcs = L"DF麗雅宋 鷗𠮟 PdCaVAWlqg"; // test surrogate | |
const wchar_t *wcs = L"DF芦鷗𠮟漣龜 Å î PdCaVAWlqg"; // test VS | |
// const wchar_t *wcs = L"DF麗雅宋 PdCaVAWlqg"; // test kerning | |
// const wchar_t *wcs = L"Consolas PdCaVAWlqg"; // test proportional | |
// const wchar_t *wcs = L"Wha't a Beautiful font ++mikaP++ is !"; | |
#else | |
const wchar_t *wcs = L"漣芦󠄀芦蘆鴎鷗叱𠮟祇󠄀祇󠄁祇祗衹"; // VS u82a6 ue0100 | |
#endif | |
const wstring wtxt(wcs); | |
#endif | |
FT_Int wskip = 0; // check and skip SVS IVS | |
FT_UInt32 wc = 0, wn = 0, wvs = 0; // must be FT_UInt32 | |
for(auto it = wtxt.begin(); it != wtxt.end(); ++it){ | |
if(wskip){ --wskip; continue; } | |
FT_UInt32 wch = *it; | |
#if 0 | |
if(wch == L' '){ loc.x += scale / 2; continue; } // not erase previous draw | |
#else | |
if(wch == L' '){ locx += scale / 2; continue; } // not erase previous draw | |
#endif | |
// care surrogate pair | |
FT_UInt16 uw = (FT_UInt16)wch; // for unsigned compare (wch is const) | |
if(uw < 0x0d800 || uw >= 0x0e000){ // not surrogate | |
wc = uw; | |
}else if(uw >= 0x0d800 && uw < 0x0dc00){ // first upper | |
wc = uw; | |
continue; | |
}else if(uw >= 0x0dc00 && uw < 0x0e000){ // second lower | |
if(!(wc >= 0x0d800 && wc < 0x0dc00)){ | |
fprintf(stderr, "first surrogate out of bounds %08x %08x\a\n", wc, uw); | |
}else{ // output wc >= u10000 && wc <= u10ffff (4bit+01 16bit) | |
wc = 0x10000 + ((wc - 0x0d800) << 10) | (uw - 0x0dc00); // 10bit 10bit | |
// wc = 0x20b9f; // debug only | |
} | |
} | |
#if 0 // debug only | |
// wc = L'\u9b31'; // for test any glyph re write it (anti optimize) 0x3760 | |
// wc = static_cast<FT_ULong>(L'\u20b9f'); // set bad value wc==0x20b9 | |
// wc = static_cast<FT_ULong>(L'𠮟'); // set bad value wc==0xd842 | |
wc = 0x20b9f; // OK | |
#endif | |
if(it + 1 != wtxt.end()){ wn = *(it + 1); | |
if(wn == 0xdb40){ // NOT (wn >= 0x0d800 && wn < 0x0dc00){ // first upper | |
wvs = wn; | |
if(it + 2 != wtxt.end()){ wn = *(it + 2); | |
if(wn >= 0x0dd00 && wn < 0x0ddf0){ // NOT (wn >= 0x0dc00 && wn < 0x0e000){ // second lower | |
wskip = 2; | |
wvs = 0x10000 + ((wvs - 0x0d800) << 10) | (wn - 0x0dc00); // 10 10 | |
}else{ | |
wvs = 0; | |
} | |
}else{ | |
wvs = 0; | |
} | |
} | |
} | |
FT_Int gid = 0; | |
#if 1 // wc=UInt32,([1(or2)]==db40),(dd00<=[2(or3)]<ddf0) ue0100-ue01ef | |
if(wvs){ | |
for(auto &v : vsel){ | |
if(v == wvs) gid = FT_Face_GetCharVariantIndex(face, wc, v); // VS | |
#if 1 // break | |
if(gid) break; | |
#else // display all VS | |
if(gid) fprintf(stderr, "VS %08x: %08x: %08x\n", v, wc, gid); | |
#endif | |
} | |
wvs = 0; | |
} | |
#endif | |
if(!gid) gid = FT_Get_Char_Index(face, wc); | |
#if 1 | |
if(!gid) fprintf(stderr, "glyph id: %08x: %08x\a\n", wc, gid); | |
#endif | |
// | FT_LOAD_NO_SCALE | FT_LOAD_NO_AUTOHINT | |
// FT_ULong flg = FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP; // get outline | |
FT_ULong flg = FT_LOAD_RENDER; // get bitmap direct | |
error = FT_Load_Glyph(face, gid, flg); | |
if(error){ | |
fprintf(stderr, "error: %d\a\n", error); | |
}else{ | |
if(slot->format == FT_GLYPH_FORMAT_OUTLINE){ | |
#if 1 | |
fprintf(stdout, "slot->outline\n"); | |
#endif | |
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); // FT_RENDER_MODE_LCD | |
#if 0 | |
loc.x += ftDrawFontSlotBitmap(dst, slot, loc, col); | |
#else | |
locx += drawBitmap(slot); | |
#endif | |
}else if(slot->format == FT_GLYPH_FORMAT_BITMAP){ | |
#if 1 | |
fprintf(stdout, "slot->bitmap\n"); | |
#endif | |
#if 0 | |
loc.x += ftDrawFontSlotBitmap(dst, slot, loc, col); | |
#else | |
locx += drawBitmap(slot); | |
#endif | |
}else{ | |
fprintf(stderr, "slot unknown\a\n"); | |
} | |
} | |
} | |
FT_Done_Face(face); | |
FT_Done_FreeType(library); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment