51#define VERSION "1.0.1"
56#define U32MAX 0xffffffff
58#define PRI_CP "U+%.4"PRIXFAST32
61#define static_assert(a, b) (assert(a))
65#define BX(shift, x) ((uintmax_t)(!!(x)) << (shift))
66#define B0(shift) BX((shift), 0)
67#define B1(shift) BX((shift), 1)
69#define GLYPH_MAX_WIDTH 16
70#define GLYPH_HEIGHT 16
73#define GLYPH_MAX_BYTE_COUNT (GLYPH_HEIGHT * GLYPH_MAX_WIDTH / 8)
79#define ASCENDER (GLYPH_HEIGHT - DESCENDER)
85#define MAX_GLYPHS 65536
88#define MAX_NAME_IDS 256
91#define FU(x) ((x) * FUPEM / GLYPH_HEIGHT)
94#define PW(x) ((x) / (GLYPH_HEIGHT / 8))
115 fputs (
"ERROR: ", stderr);
117 va_start (args, reason);
118 vfprintf (stderr, reason, args);
136 byte *begin, *next, *end;
158 fail (
"Failed to initialize buffers.");
190 assert (initialCapacity > 0);
206 void *extended = realloc (
allBuffers, newSize);
208 fail (
"Failed to create new buffers.");
215 buf->begin = malloc (initialCapacity);
217 fail (
"Failed to allocate %zu bytes of memory.", initialCapacity);
218 buf->capacity = initialCapacity;
219 buf->next = buf->begin;
220 buf->end = buf->begin + initialCapacity;
241 if (buf->end - buf->next >= needed)
243 ptrdiff_t occupied = buf->next - buf->begin;
244 size_t required = occupied + needed;
245 if (required < needed)
246 fail (
"Cannot allocate %zu + %zu bytes of memory.", occupied, needed);
247 if (required > SIZE_MAX / 2)
248 buf->capacity = required;
249 else while (buf->capacity < required)
251 void *extended = realloc (buf->begin, buf->capacity);
253 fail (
"Failed to allocate %zu bytes of memory.", buf->capacity);
254 buf->begin = extended;
255 buf->next = buf->begin + occupied;
256 buf->end = buf->begin + buf->capacity;
266countBufferedBytes (
const Buffer *buf)
268 return buf->next - buf->begin;
278getBufferHead (
const Buffer *buf)
290getBufferTail (
const Buffer *buf)
306getBufferSlot (
Buffer *buf,
size_t slotSize)
309 void *slot = buf->next;
310 buf->next += slotSize;
325 buf->next = buf->begin;
350#define defineStore(name, type) \
351void name (Buffer *buf, type value) \
353 type *slot = getBufferSlot (buf, sizeof value); \
374cacheU (
Buffer *buf, uint_fast32_t value,
int bytes)
376 assert (1 <= bytes && bytes <= 4);
380 case 4: *buf->next++ = value >> 24 & 0xff;
381 case 3: *buf->next++ = value >> 16 & 0xff;
382 case 2: *buf->next++ = value >> 8 & 0xff;
383 case 1: *buf->next++ = value & 0xff;
399 storeU8 (buf, value & 0xff);
414 cacheU (buf, value, 2);
429 cacheU (buf, value, 4);
462 if (-107 <= value && value <= 107)
464 else if (108 <= value && value <= 1131)
466 cacheU8 (buf, (value - 108) / 256 + 247);
467 cacheU8 (buf, (value - 108) % 256);
469 else if (-32768 <= value && value <= 32767)
474 else if (-2147483647 <= value && value <= 2147483647)
494 memset (buf->next, 0, count);
512 memcpy (buf->next, src, count);
525 size_t length = countBufferedBytes (bufSrc);
527 memcpy (bufDest->next, bufSrc->begin, length);
528 bufDest->next += length;
540 if (fwrite (bytes, count, 1, file) != 1 && count != 0)
541 fail (
"Failed to write %zu bytes to output file.", count);
578 (value >> 24) & 0xff,
579 (value >> 16) & 0xff,
598writeBuffer (
const Buffer *buf, FILE *file)
600 writeBytes (getBufferHead (buf), countBufferedBytes (buf), file);
632 uint_fast32_t glyphCount;
672static inline uint_fast32_t tagAsU32 (
const char tag[
static 4])
675 r |= (tag[0] & 0xff) << 24;
676 r |= (tag[1] & 0xff) << 16;
677 r |= (tag[2] & 0xff) << 8;
678 r |= (tag[3] & 0xff);
696 Table *table = getBufferSlot (font->tables, sizeof (
Table));
697 table->tag = tagAsU32 (tag);
698 table->content = content;
713 const char *
const cffOrder[] = {
"head",
"hhea",
"maxp",
"OS/2",
"name",
714 "cmap",
"post",
"CFF ",NULL};
715 const char *
const truetypeOrder[] = {
"head",
"hhea",
"maxp",
"OS/2",
716 "hmtx",
"LTSH",
"VDMX",
"hdmx",
"cmap",
"fpgm",
"prep",
"cvt ",
"loca",
717 "glyf",
"kern",
"name",
"post",
"gasp",
"PCLT",
"DSIG",NULL};
718 const char *
const *
const order = isCFF ? cffOrder : truetypeOrder;
719 Table *unordered = getBufferHead (font->tables);
720 const Table *
const tablesEnd = getBufferTail (font->tables);
721 for (
const char *
const *p = order; *p; p++)
723 uint_fast32_t tag = tagAsU32 (*p);
724 for (
Table *t = unordered; t < tablesEnd; t++)
730 Table temp = *unordered;
749 uint_least32_t tag, offset, length, checksum;
769 const struct TableRecord *
const ra = a, *
const rb = b;
770 int gt = ra->tag > rb->tag;
771 int lt = ra->tag < rb->tag;
788 FILE *file = fopen (fileName,
"wb");
790 fail (
"Failed to open file '%s'.", fileName);
791 const Table *
const tables = getBufferHead (font->tables);
792 const Table *
const tablesEnd = getBufferTail (font->tables);
793 size_t tableCount = tablesEnd - tables;
794 assert (0 < tableCount && tableCount <=
U16MAX);
795 size_t offset = 12 + 16 * tableCount;
796 uint_fast32_t totalChecksum = 0;
799 for (
size_t i = 0; i < tableCount; i++)
802 getBufferSlot (tableRecords,
sizeof *record);
803 record->tag = tables[i].tag;
804 size_t length = countBufferedBytes (tables[i].content);
805 #if SIZE_MAX > U32MAX
807 fail (
"Table offset exceeded 4 GiB.");
809 fail (
"Table size exceeded 4 GiB.");
811 record->length = length;
812 record->checksum = 0;
813 const byte *p = getBufferHead (tables[i].content);
814 const byte *
const end = getBufferTail (tables[i].content);
817 #define addByte(shift) \
820 record->checksum += (uint_fast32_t)*p++ << (shift);
830 cacheZeros (tables[i].content, (~length + 1U) & 3U);
831 record->offset = offset;
832 offset += countBufferedBytes (tables[i].content);
833 totalChecksum += record->checksum;
835 struct TableRecord *records = getBufferHead (tableRecords);
836 qsort (records, tableCount,
sizeof *records,
byTableTag);
838 uint_fast32_t sfntVersion = isCFF ? 0x4f54544f : 0x00010000;
840 totalChecksum += sfntVersion;
841 uint_fast16_t entrySelector = 0;
842 for (
size_t k = tableCount; k != 1; k >>= 1)
844 uint_fast16_t searchRange = 1 << (entrySelector + 4);
845 uint_fast16_t rangeShift = (tableCount - (1 << entrySelector)) << 4;
850 totalChecksum += (uint_fast32_t)tableCount << 16;
851 totalChecksum += searchRange;
852 totalChecksum += (uint_fast32_t)entrySelector << 16;
853 totalChecksum += rangeShift;
855 for (
size_t i = 0; i < tableCount; i++)
859 writeU32 (records[i].checksum, file);
862 totalChecksum += records[i].tag;
863 totalChecksum += records[i].checksum;
864 totalChecksum += records[i].offset;
865 totalChecksum += records[i].length;
868 for (
const Table *table = tables; table < tablesEnd; table++)
870 if (table->tag == 0x68656164)
872 byte *begin = getBufferHead (table->content);
873 byte *end = getBufferTail (table->content);
875 writeU32 (0xb1b0afbaU - totalChecksum, file);
876 writeBytes (begin + 12, end - (begin + 12), file);
879 writeBuffer (table->content, file);
895nibbleValue (
char nibble)
897 if (isdigit (nibble))
899 nibble = toupper (nibble);
900 return nibble -
'A' + 10;
922 uint_fast8_t digitCount = 0;
926 if (isxdigit (c) && ++digitCount <= 6)
928 *codePoint = (*codePoint << 4) | nibbleValue (c);
931 if (c ==
':' && digitCount > 0)
938 fail (
"%s: Unexpected end of file.", fileName);
940 fail (
"%s: Read error.", fileName);
942 fail (
"%s: Unexpected character: %#.2x.", fileName, (
unsigned)c);
968 FILE *file = fopen (fileName,
"r");
970 fail (
"Failed to open file '%s'.", fileName);
971 uint_fast32_t glyphCount = 1;
972 uint_fast8_t maxByteCount = 0;
974 const byte bitmap[] =
"\0\0\0~fZZzvv~vv~\0\0";
975 const size_t byteCount =
sizeof bitmap - 1;
978 Glyph *notdef = getBufferSlot (font->glyphs, sizeof (
Glyph));
979 memcpy (notdef->
bitmap, bitmap, byteCount);
980 notdef->
byteCount = maxByteCount = byteCount;
987 uint_fast32_t codePoint;
991 fail (
"OpenType does not support more than %lu glyphs.",
993 Glyph *glyph = getBufferSlot (font->glyphs, sizeof (
Glyph));
999 for (
byte *p = glyph->
bitmap;; p++)
1002 if (isxdigit (h = getc (file)) && isxdigit (l = getc (file)))
1005 fail (
"Hex stream of "PRI_CP" is too long.", codePoint);
1006 *p = nibbleValue (h) << 4 | nibbleValue (l);
1008 else if (h ==
'\n' || (h == EOF && feof (file)))
1010 else if (ferror (file))
1011 fail (
"%s: Read error.", fileName);
1013 fail (
"Hex stream of "PRI_CP" is invalid.", codePoint);
1016 fail (
"Hex length of "PRI_CP" is indivisible by glyph height %d.",
1021 if (glyphCount == 1)
1022 fail (
"No glyph is specified.");
1023 font->glyphCount = glyphCount;
1024 font->maxWidth =
PW (maxByteCount);
1042 const Glyph *
const ga = a, *
const gb = b;
1064 FILE *file = fopen (fileName,
"r");
1066 fail (
"Failed to open file '%s'.", fileName);
1067 Glyph *glyphs = getBufferHead (font->glyphs);
1068 const Glyph *
const endGlyph = glyphs + font->glyphCount;
1069 Glyph *nextGlyph = &glyphs[1];
1072 uint_fast32_t codePoint;
1075 Glyph *glyph = nextGlyph;
1076 if (glyph == endGlyph || glyph->
codePoint != codePoint)
1080 glyph = bsearch (&key, glyphs + 1, font->glyphCount - 1,
1083 fail (
"Glyph "PRI_CP" is positioned but not defined.",
1086 nextGlyph = glyph + 1;
1088 if (!fgets (s,
sizeof s, file))
1089 fail (
"%s: Read error.", fileName);
1091 const long value = strtol (s, &end, 10);
1092 if (*end !=
'\n' && *end !=
'\0')
1093 fail (
"Position of glyph "PRI_CP" is invalid.", codePoint);
1098 if (value < -GLYPH_MAX_WIDTH || value > 0)
1099 fail (
"Position of glyph "PRI_CP" is out of range.", codePoint);
1121 Glyph *glyphs = getBufferHead (font->glyphs);
1122 const Glyph *
const glyphsEnd = getBufferTail (font->glyphs);
1124 qsort (glyphs, glyphsEnd - glyphs,
sizeof *glyphs,
byCodePoint);
1125 for (
const Glyph *glyph = glyphs; glyph < glyphsEnd - 1; glyph++)
1127 if (glyph[0].codePoint == glyph[1].codePoint)
1128 fail (
"Duplicate code point: "PRI_CP".", glyph[0].codePoint);
1129 assert (glyph[0].codePoint < glyph[1].codePoint);
1163 enum Direction {RIGHT, LEFT, DOWN, UP};
1166 const pixels_t dx[] = {1, -1, 0, 0}, dy[] = {0, 0, -1, 1};
1169 const uint_fast8_t bytesPerRow = byteCount /
GLYPH_HEIGHT;
1170 const pixels_t glyphWidth = bytesPerRow * 8;
1173 #if GLYPH_MAX_WIDTH < 32
1174 typedef uint_fast32_t row_t;
1175 #elif GLYPH_MAX_WIDTH < 64
1176 typedef uint_fast64_t row_t;
1178 #error GLYPH_MAX_WIDTH is too large.
1183 for (
pixels_t b = 0; b < bytesPerRow; b++)
1184 pixels[row] = pixels[row] << 8 | *bitmap++;
1187 const row_t *lower = pixels, *upper = pixels + 1;
1190 const row_t m = (fillSide ==
FILL_RIGHT) - 1;
1191 vectors[RIGHT][row] = (m ^ (*lower << 1)) & (~m ^ (*upper << 1));
1192 vectors[LEFT ][row] = (m ^ (*upper )) & (~m ^ (*lower ));
1193 vectors[DOWN ][row] = (m ^ (*lower )) & (~m ^ (*lower << 1));
1194 vectors[UP ][row] = (m ^ (*upper << 1)) & (~m ^ (*upper ));
1198 graph_t selection = {0};
1199 const row_t x0 = (row_t)1 << glyphWidth;
1202 #define getRowBit(rows, x, y) ((rows)[(y)] & x0 >> (x))
1205 #define flipRowBit(rows, x, y) ((rows)[(y)] ^= x0 >> (x))
1209 for (
pixels_t x = 0; x <= glyphWidth; x++)
1211 assert (!getRowBit (vectors[LEFT], x, y));
1212 assert (!getRowBit (vectors[UP], x, y));
1213 enum Direction initial;
1215 if (getRowBit (vectors[RIGHT], x, y))
1217 else if (getRowBit (vectors[DOWN], x, y))
1223 U16MAX,
"potential overflow");
1225 uint_fast16_t lastPointCount = 0;
1226 for (
bool converged =
false;;)
1228 uint_fast16_t pointCount = 0;
1229 enum Direction heading = initial;
1235 storePixels (result, tx);
1236 storePixels (result, ty);
1241 flipRowBit (vectors[heading], tx, ty);
1244 }
while (getRowBit (vectors[heading], tx, ty));
1245 if (tx == x && ty == y)
1247 static_assert ((UP ^ DOWN) == 1 && (LEFT ^ RIGHT) == 1,
1249 heading = (heading & 2) ^ 2;
1250 heading |= !!getRowBit (selection, tx, ty);
1251 heading ^= !getRowBit (vectors[heading], tx, ty);
1252 assert (getRowBit (vectors[heading], tx, ty));
1253 flipRowBit (selection, tx, ty);
1258 converged = pointCount == lastPointCount;
1259 lastPointCount = pointCount;
1278 for (
size_t *i = sizes + 1; *i; i++)
1280 if (*p > 2147483647U)
1281 fail (
"CFF table is too large.");
1295 const char *strings[] = {
"Adobe",
"Identity", names[6]};
1297 #define stringCount (sizeof strings / sizeof *strings)
1298 static_assert (stringCount <=
U16MAX,
"too many strings");
1300 size_t lengths[stringCount];
1301 for (
size_t i = 0; i < stringCount; i++)
1303 assert (strings[i]);
1304 lengths[i] = strlen (strings[i]);
1305 offset += lengths[i];
1307 int offsetSize = 1 + (offset > 0xff)
1309 + (offset > 0xffffff);
1312 cacheU (buf, offset = 1, offsetSize);
1313 for (
size_t i = 0; i < stringCount; i++)
1314 cacheU (buf, offset += lengths[i], offsetSize);
1315 for (
size_t i = 0; i < stringCount; i++)
1332 assert (0 < version && version <= 2);
1334 addTable (font, version == 1 ?
"CFF " :
"CFF2", cff);
1337 #define cacheCFF32(buf, x) (cacheU8 ((buf), 29), cacheU32 ((buf), (x)))
1340 const pixels_t defaultWidth = 16, nominalWidth = 8;
1344 size_t stringsSize = countBufferedBytes (strings);
1345 const char *cffName = names[6];
1347 size_t nameLength = strlen (cffName);
1348 size_t namesSize = nameLength + 5;
1350 size_t offsets[] = {4, namesSize, 45, stringsSize, 2, 5, 8, 32, 4, 0};
1358 assert (countBufferedBytes (cff) == offsets[0]);
1363 if (nameLength + 1 > 255)
1364 fail (
"PostScript name is too long.");
1365 cacheU8 (cff, nameLength + 1);
1368 assert (countBufferedBytes (cff) == offsets[1]);
1378 cacheCFF32 (cff, font->glyphCount);
1380 cacheCFF32 (cff, offsets[6]);
1382 cacheCFF32 (cff, offsets[5]);
1384 cacheCFF32 (cff, offsets[4]);
1386 cacheCFF32 (cff, offsets[8]);
1389 assert (countBufferedBytes (cff) == offsets[2]);
1394 assert (countBufferedBytes (cff) == offsets[3]);
1396 assert (countBufferedBytes (cff) == offsets[4]);
1401 cacheU16 (cff, font->glyphCount - 2);
1404 assert (countBufferedBytes (cff) == offsets[5]);
1412 assert (countBufferedBytes (cff) == offsets[6]);
1421 const byte unit[] = {0x1e,0x15,0x62,0x5c,0x6f};
1430 cacheCFF32 (cff, offsets[7]);
1433 assert (countBufferedBytes (cff) == offsets[7]);
1440 assert (countBufferedBytes (cff) == offsets[8]);
1444 assert (version == 2);
1446 size_t offsets[] = {5, 21, 4, 10, 0};
1452 cacheU16 (cff, offsets[1] - offsets[0]);
1454 assert (countBufferedBytes (cff) == offsets[0]);
1456 const byte unit[] = {0x1e,0x15,0x62,0x5c,0x6f};
1469 assert (countBufferedBytes (cff) == offsets[1]);
1471 assert (countBufferedBytes (cff) == offsets[2]);
1481 assert (countBufferedBytes (cff) == offsets[3]);
1487 const Glyph *glyph = getBufferHead (font->glyphs);
1488 const Glyph *
const endGlyph = glyph + font->glyphCount;
1489 for (; glyph < endGlyph; glyph++)
1492 storeU32 (offsets, countBufferedBytes (charstrings) + 1);
1496 resetBuffer (outline);
1498 enum CFFOp {rmoveto=21, hmoveto=22, vmoveto=4, hlineto=6,
1499 vlineto=7, endchar=14};
1500 enum CFFOp pendingOp = 0;
1501 const int STACK_LIMIT = version == 1 ? 48 : 513;
1503 bool isDrawing =
false;
1505 if (version == 1 && width != defaultWidth)
1510 for (
const pixels_t *p = getBufferHead (outline),
1511 *
const end = getBufferTail (outline); p < end;)
1532 assert (!(isDrawing && s == 3));
1538 const enum CFFOp moves[] = {0, hmoveto, vmoveto,
1540 cacheU8 (charstrings, moves[s]);
1543 else if (!pendingOp)
1544 pendingOp = (
enum CFFOp[]){0, hlineto, vlineto}[s];
1546 else if (!isDrawing)
1550 cacheU8 (charstrings, hmoveto);
1553 if (op ==
OP_CLOSE || stackSize >= STACK_LIMIT)
1555 assert (stackSize <= STACK_LIMIT);
1556 cacheU8 (charstrings, pendingOp);
1563 cacheU8 (charstrings, endchar);
1565 size_t lastOffset = countBufferedBytes (charstrings) + 1;
1566 #if SIZE_MAX > U32MAX
1568 fail (
"CFF data exceeded size limit.");
1570 storeU32 (offsets, lastOffset);
1571 int offsetSize = 1 + (lastOffset > 0xff)
1572 + (lastOffset > 0xffff)
1573 + (lastOffset > 0xffffff);
1575 cacheU (cff, font->glyphCount, version * 2);
1577 const uint_least32_t *p = getBufferHead (offsets);
1578 const uint_least32_t *
const end = getBufferTail (offsets);
1579 for (; p < end; p++)
1580 cacheU (cff, *p, offsetSize);
1598 uint_fast16_t *maxPoints, uint_fast16_t *maxContours)
1610 Glyph *
const glyphs = getBufferHead (font->glyphs);
1611 const Glyph *
const glyphsEnd = getBufferTail (font->glyphs);
1612 for (
Glyph *glyph = glyphs; glyph < glyphsEnd; glyph++)
1614 cacheU32 (loca, countBufferedBytes (glyf));
1619 resetBuffer (endPoints);
1620 resetBuffer (flags);
1623 resetBuffer (outline);
1625 uint_fast32_t pointCount = 0, contourCount = 0;
1626 for (
const pixels_t *p = getBufferHead (outline),
1627 *
const end = getBufferTail (outline); p < end;)
1633 assert (contourCount <=
U16MAX);
1634 cacheU16 (endPoints, pointCount - 1);
1639 assert (pointCount <=
U16MAX);
1641 uint_fast8_t pointFlags =
1655 cacheU8 (xs,
FU (x > rx ? x - rx : rx - x));
1657 cacheU8 (ys,
FU (y > ry ? y - ry : ry - y));
1658 if (x < xMin) xMin = x;
1659 if (y < yMin) yMin = y;
1660 if (x > xMax) xMax = x;
1661 if (y > yMax) yMax = y;
1665 if (contourCount == 0)
1667 glyph->lsb = glyph->pos + xMin;
1678 if (pointCount > *maxPoints)
1679 *maxPoints = pointCount;
1680 if (contourCount > *maxContours)
1681 *maxContours = contourCount;
1683 cacheU32 (loca, countBufferedBytes (glyf));
1711 assert (countBufferedBytes (glyf) % 2 == 0);
1712 for (uint_fast32_t i = 1; i <= font->glyphCount; i++)
1713 cacheU16 (loca, countBufferedBytes (glyf) / 2);
1730 const Glyph *
const glyphs = getBufferHead (font->glyphs);
1731 const Glyph *
const glyphsEnd = getBufferTail (font->glyphs);
1732 size_t bitmapsSize = 0;
1733 for (
const Glyph *glyph = glyphs; glyph < glyphsEnd; glyph++)
1734 bitmapsSize += glyph->byteCount;
1739 uint_fast8_t byteCount = 0;
1741 bool combining =
false;
1744 for (
const Glyph *glyph = glyphs; glyph < glyphsEnd; glyph++)
1746 if (glyph->byteCount != byteCount || glyph->pos != pos ||
1747 glyph->combining != combining)
1749 storeU16 (rangeHeads, glyph - glyphs);
1750 storeU32 (offsets, countBufferedBytes (ebdt));
1751 byteCount = glyph->byteCount;
1753 combining = glyph->combining;
1757 const uint_least16_t *ranges = getBufferHead (rangeHeads);
1758 const uint_least16_t *rangesEnd = getBufferTail (rangeHeads);
1759 uint_fast32_t rangeCount = rangesEnd - ranges;
1760 storeU16 (rangeHeads, font->glyphCount);
1768 cacheU32 (eblc, (8 + 20) * rangeCount);
1774 cacheU8 (eblc, font->maxWidth);
1788 cacheU8 (eblc, font->maxWidth);
1800 cacheU16 (eblc, font->glyphCount - 1);
1807 uint_fast32_t offset = rangeCount * 8;
1808 for (
const uint_least16_t *p = ranges; p < rangesEnd; p++)
1817 const uint_least32_t *offset = getBufferHead (offsets);
1818 for (
const uint_least16_t *p = ranges; p < rangesEnd; p++)
1820 const Glyph *glyph = &glyphs[*p];
1864 const uint_fast16_t flags =
1891 const uint_fast16_t macStyle =
1955 uint_fast16_t maxContours)
1959 cacheU32 (maxp, isCFF ? 0x00005000 : 0x00010000);
1995 const uint_fast16_t typeFlags =
2019 const byte panose[] =
2043 const uint_fast16_t selection =
2057 const Glyph *glyphs = getBufferHead (font->glyphs);
2058 uint_fast32_t first = glyphs[1].
codePoint;
2059 uint_fast32_t last = glyphs[font->glyphCount - 1].
codePoint;
2091 const Glyph *
const glyphs = getBufferHead (font->glyphs);
2092 const Glyph *
const glyphsEnd = getBufferTail (font->glyphs);
2093 for (
const Glyph *glyph = glyphs; glyph < glyphsEnd; glyph++)
2095 int_fast16_t aw = glyph->combining ? 0 :
PW (glyph->byteCount);
2111 Glyph *
const glyphs = getBufferHead (font->glyphs);
2113 uint_fast32_t rangeCount = 0;
2114 uint_fast32_t bmpRangeCount = 1;
2116 for (uint_fast16_t i = 1; i < font->glyphCount; i++)
2118 if (glyphs[i].codePoint != glyphs[i - 1].codePoint + 1)
2120 storeU16 (rangeHeads, i);
2122 bmpRangeCount += glyphs[i].
codePoint < 0xffff;
2128 bool hasFormat12 = glyphs[font->glyphCount - 1].
codePoint > 0xffff;
2134 cacheU32 (cmap, 12 + 8 * hasFormat12);
2140 cacheU32 (cmap, 36 + 8 * bmpRangeCount);
2142 const uint_least16_t *ranges = getBufferHead (rangeHeads);
2143 const uint_least16_t *
const rangesEnd = getBufferTail (rangeHeads);
2144 storeU16 (rangeHeads, font->glyphCount);
2147 cacheU16 (cmap, 16 + 8 * bmpRangeCount);
2149 if (bmpRangeCount * 2 >
U16MAX)
2150 fail (
"Too many ranges in 'cmap' table.");
2151 cacheU16 (cmap, bmpRangeCount * 2);
2152 uint_fast16_t searchRange = 1, entrySelector = -1;
2153 while (searchRange <= bmpRangeCount)
2160 cacheU16 (cmap, bmpRangeCount * 2 - searchRange);
2162 const uint_least16_t *p = ranges;
2163 for (p++; p < rangesEnd && glyphs[*p].
codePoint < 0xffff; p++)
2164 cacheU16 (cmap, glyphs[*p - 1].codePoint);
2165 uint_fast32_t cp = glyphs[*p - 1].
codePoint;
2173 for (uint_fast32_t i = 0; i < bmpRangeCount - 1; i++)
2174 cacheU16 (cmap, glyphs[ranges[i]].codePoint);
2178 const uint_least16_t *p = ranges;
2179 for (; p < rangesEnd && glyphs[*p].
codePoint < 0xffff; p++)
2180 cacheU16 (cmap, *p - glyphs[*p].codePoint);
2181 uint_fast16_t delta = 1;
2182 if (p < rangesEnd && *p == 0xffff)
2187 for (uint_least16_t i = 0; i < bmpRangeCount; i++)
2195 cacheU32 (cmap, 16 + 12 * rangeCount);
2200 for (
const uint_least16_t *p = ranges; p < rangesEnd; p++)
2202 cacheU32 (cmap, glyphs[*p].codePoint);
2203 cacheU32 (cmap, glyphs[p[1] - 1].codePoint);
2318 for (
const char *p = str; *p; p++)
2328 for (; c & mask; mask >>= 1)
2330 if (length == 1 || length > 4)
2331 fail (
"Ill-formed UTF-8 sequence.");
2332 uint_fast32_t codePoint = c & (mask - 1);
2333 for (
int i = 1; i < length; i++)
2336 if ((c & 0xc0) != 0x80)
2337 fail (
"Ill-formed UTF-8 sequence.");
2338 codePoint = (codePoint << 6) | (c & 0x3f);
2340 const int lowerBits = length==2 ? 7 : length==3 ? 11 : 16;
2341 if (codePoint >> lowerBits == 0)
2342 fail (
"Ill-formed UTF-8 sequence.");
2343 if (codePoint >= 0xd800 && codePoint <= 0xdfff)
2344 fail (
"Ill-formed UTF-8 sequence.");
2345 if (codePoint > 0x10ffff)
2346 fail (
"Ill-formed UTF-8 sequence.");
2347 if (codePoint > 0xffff)
2349 cacheU16 (buf, 0xd800 | (codePoint - 0x10000) >> 10);
2350 cacheU16 (buf, 0xdc00 | (codePoint & 0x3ff));
2370 size_t nameStringCount = 0;
2372 nameStringCount += !!nameStrings[i];
2375 cacheU16 (name, 2 * 3 + 12 * nameStringCount);
2380 if (!nameStrings[i])
2382 size_t offset = countBufferedBytes (stringData);
2384 size_t length = countBufferedBytes (stringData) - offset;
2386 fail (
"Name strings are too long.");
2408 printf (
"hex2otf (GNU Unifont) %s\n",
VERSION);
2409 printf (
"Copyright \u00A9 2022 \u4F55\u5FD7\u7FD4 (He Zhixiang)\n");
2410 printf (
"License GPLv2+: GNU GPL version 2 or later\n");
2411 printf (
"<https://gnu.org/licenses/gpl.html>\n");
2412 printf (
"This is free software: you are free to change and\n");
2413 printf (
"redistribute it. There is NO WARRANTY, to the extent\n");
2414 printf (
"permitted by law.\n");
2416 exit (EXIT_SUCCESS);
2427 printf (
"Synopsis: hex2otf <options>:\n\n");
2428 printf (
" hex=<filename> Specify Unifont .hex input file.\n");
2429 printf (
" pos=<filename> Specify combining file. (Optional)\n");
2430 printf (
" out=<filename> Specify output font file.\n");
2431 printf (
" format=<f1>,<f2>,... Specify font format(s); values:\n");
2434 printf (
" truetype\n");
2435 printf (
" blank\n");
2436 printf (
" bitmap\n");
2439 printf (
"\nExample:\n\n");
2440 printf (
" hex2otf hex=Myfont.hex out=Myfont.otf format=cff\n\n");
2441 printf (
"For more information, consult the hex2otf(1) man page.\n\n");
2443 exit (EXIT_SUCCESS);
2455 bool truetype, blankOutline, bitmap, gpos, gsub;
2457 const char *hex, *pos, *out;
2473 if (*operand++ != *key++)
2475 if (!*operand || *operand++ == delimiter)
2503 const char *format = NULL;
2506 const char *
const key;
2507 const char **
const value;
2513 {
"format", &format},
2516 for (
char *
const *argp = argv + 1; *argp; argp++)
2518 const char *
const arg = *argp;
2519 struct StringArg *p;
2520 const char *value = NULL;
2521 if (strcmp (arg,
"--help") == 0)
2523 if (strcmp (arg,
"--version") == 0)
2525 for (p = strArgs; p->key; p++)
2531 fail (
"Empty argument: '%s'.", p->key);
2533 fail (
"Duplicate argument: '%s'.", p->key);
2539 unsigned long id = strtoul (arg, &endptr, 10);
2540 if (endptr == arg ||
id >=
MAX_NAME_IDS || *endptr !=
'=')
2541 fail (
"Invalid argument: '%s'.", arg);
2543 if (opt.nameStrings[
id])
2544 fail (
"Duplicate name ID: %lu.",
id);
2545 opt.nameStrings[id] = endptr;
2549 fail (
"Hex file is not specified.");
2550 if (opt.pos && opt.pos[0] ==
'\0')
2553 fail (
"Output file is not specified.");
2555 fail (
"Format is not specified.");
2557 if (!opt.nameStrings[p->id])
2558 opt.nameStrings[p->id] = p->str;
2559 bool cff =
false, cff2 =
false;
2562 const char *
const key;
2568 {
"truetype", &opt.truetype},
2569 {
"blank", &opt.blankOutline},
2570 {
"bitmap", &opt.bitmap},
2571 {
"gpos", &opt.gpos},
2572 {
"gsub", &opt.gsub},
2577 const struct Symbol *p;
2578 const char *next = NULL;
2579 for (p = symbols; p->key; p++)
2580 if ((next =
matchToken (format, p->key,
',')))
2583 fail (
"Invalid format.");
2587 if (cff + cff2 + opt.truetype + opt.blankOutline > 1)
2588 fail (
"At most one outline format can be accepted.");
2589 if (!(cff || cff2 || opt.truetype || opt.bitmap))
2590 fail (
"Invalid format.");
2591 opt.cff = cff + cff2 * 2;
2614 uint_fast16_t maxPoints = 0, maxContours = 0;
2623 fillCFF (&font, opt.cff, opt.nameStrings);
2626 if (opt.blankOutline)
2640 return EXIT_SUCCESS;
#define U16MAX
Maximum UTF-16 code point value.
void organizeTables(Font *font, bool isCFF)
Sort tables according to OpenType recommendations.
void cacheU32(Buffer *buf, uint_fast32_t value)
Append four unsigned bytes to the end of a byte array.
Buffer * allBuffers
Initial allocation of empty array of buffer pointers.
#define MAX_NAME_IDS
Name IDs 0-255 are used for standard names.
void fillGsubTable(Font *font)
Fill a "GSUB" font table.
void writeFont(Font *font, bool isCFF, const char *fileName)
Write OpenType font to output file.
void cacheU16(Buffer *buf, uint_fast16_t value)
Append two unsigned bytes to the end of a byte array.
const char * NameStrings[MAX_NAME_IDS]
Array of OpenType names indexed directly by Name IDs.
unsigned char byte
Definition of "byte" type as an unsigned char.
int byCodePoint(const void *a, const void *b)
Compare two Unicode code points to determine which is greater.
void printHelp()
Print help message to stdout and then exit.
void cacheZeros(Buffer *buf, size_t count)
Append 1 to 4 bytes of zeroes to a buffer, for padding.
void fillPostTable(Font *font)
Fill a "post" font table.
int main(int argc, char *argv[])
The main function.
#define defineStore(name, type)
Temporary define to look up an element in an array of given type.
size_t nextBufferIndex
Index number to tail element of Buffer * array.
#define B0(shift)
Clear a given bit in a word.
void cacheStringAsUTF16BE(Buffer *buf, const char *str)
Cache a string as a big-ending UTF-16 surrogate pair.
#define MAX_GLYPHS
An OpenType font has at most 65536 glyphs.
#define VERSION
Program version, for "--version" option.
void addTable(Font *font, const char tag[static 4], Buffer *content)
Add a TrueType or OpenType table to the font.
#define B1(shift)
Set a given bit in a word.
ContourOp
Specify the current contour drawing operation.
@ OP_POINT
Add one more (x,y) point to the contor being drawn.
@ OP_CLOSE
Close the current contour path that was being drawn.
void fillHheaTable(Font *font, pixels_t xMin)
Fill a "hhea" font table.
void fail(const char *reason,...)
Print an error message on stderr, then exit.
void fillTrueType(Font *font, enum LocaFormat *format, uint_fast16_t *maxPoints, uint_fast16_t *maxContours)
Add a TrueType table to a font.
void fillCFF(Font *font, int version, const NameStrings names)
Add a CFF table to a font.
void fillHeadTable(Font *font, enum LocaFormat locaFormat, pixels_t xMin)
Fill a "head" font table.
void initBuffers(size_t count)
Initialize an array of buffer pointers to all zeroes.
void cacheCFFOperand(Buffer *buf, int_fast32_t value)
Cache charstring number encoding in a CFF buffer.
void cacheBuffer(Buffer *restrict bufDest, const Buffer *restrict bufSrc)
Append bytes of a table to a byte buffer.
void buildOutline(Buffer *result, const byte bitmap[], const size_t byteCount, const enum FillSide fillSide)
Build a glyph outline.
void fillCmapTable(Font *font)
Fill a "cmap" font table.
#define FUPEM
Font units per em.
struct Font Font
Data structure to hold information for one font.
#define GLYPH_MAX_WIDTH
Maximum glyph width, in pixels.
FillSide
Fill to the left side (CFF) or right side (TrueType) of a contour.
@ FILL_RIGHT
Draw outline clockwise (TrueType).
@ FILL_LEFT
Draw outline counter-clockwise (CFF, PostScript).
void fillGposTable(Font *font)
Fill a "GPOS" font table.
#define BX(shift, x)
Truncate & shift word.
void sortGlyphs(Font *font)
Sort the glyphs in a font by Unicode code point.
void fillNameTable(Font *font, NameStrings nameStrings)
Fill a "name" font table.
#define PW(x)
Convert glyph byte count to pixel width.
#define U32MAX
Maximum UTF-32 code point value.
#define GLYPH_HEIGHT
Maximum glyph height, in pixels.
LocaFormat
Index to Location ("loca") offset information.
@ LOCA_OFFSET16
Offset to location is a 16-bit Offset16 value.
@ LOCA_OFFSET32
Offset to location is a 32-bit Offset32 value.
struct Buffer Buffer
Generic data structure for a linked list of buffer elements.
void writeU16(uint_fast16_t value, FILE *file)
Write an unsigned 16-bit value to an output file.
void cacheU8(Buffer *buf, uint_fast8_t value)
Append one unsigned byte to the end of a byte array.
#define FU(x)
Convert pixels to font units.
struct Glyph Glyph
Data structure to hold data for one bitmap glyph.
#define DESCENDER
Count of pixels below baseline.
size_t bufferCount
Number of buffers in a Buffer * array.
void cacheBytes(Buffer *restrict buf, const void *restrict src, size_t count)
Append a string of bytes to a buffer.
void writeU32(uint_fast32_t value, FILE *file)
Write an unsigned 32-bit value to an output file.
void prepareOffsets(size_t *sizes)
Prepare 32-bit glyph offsets in a font table.
void fillHmtxTable(Font *font)
Fill an "hmtx" font table.
struct Options Options
Data structure to hold options for OpenType font output.
void printVersion()
Print program version string on stdout.
Buffer * prepareStringIndex(const NameStrings names)
Prepare a font name string index.
struct Table Table
Data structure for an OpenType table.
void fillBlankOutline(Font *font)
Create a dummy blank outline in a font table.
void fillOS2Table(Font *font)
Fill an "OS/2" font table.
int_least8_t pixels_t
This type must be able to represent max(GLYPH_MAX_WIDTH, GLYPH_HEIGHT).
Options parseOptions(char *const argv[const])
Parse command line options.
void freeBuffer(Buffer *buf)
Free the memory previously allocated for a buffer.
void cleanBuffers()
Free all allocated buffer pointers.
#define ASCENDER
Count of pixels above baseline.
#define GLYPH_MAX_BYTE_COUNT
Number of bytes to represent one bitmap glyph as a binary array.
void readGlyphs(Font *font, const char *fileName)
Read glyph definitions from a Unifont .hex format file.
bool readCodePoint(uint_fast32_t *codePoint, const char *fileName, FILE *file)
Read up to 6 hexadecimal digits and a colon from file.
void writeBytes(const byte bytes[], size_t count, FILE *file)
Write an array of bytes to an output file.
void ensureBuffer(Buffer *buf, size_t needed)
Ensure that the buffer has at least the specified minimum size.
Buffer * newBuffer(size_t initialCapacity)
Create a new buffer.
int byTableTag(const void *a, const void *b)
Compare tables by 4-byte unsigned table tag value.
const char * matchToken(const char *operand, const char *key, char delimiter)
Match a command line option with its key for enabling.
#define PRI_CP
Format string to print Unicode code point.
void positionGlyphs(Font *font, const char *fileName, pixels_t *xMin)
Position a glyph within a 16-by-16 pixel bounding box.
void fillBitmap(Font *font)
Fill OpenType bitmap data and location tables.
void fillMaxpTable(Font *font, bool isCFF, uint_fast16_t maxPoints, uint_fast16_t maxContours)
Fill a "maxp" font table.
hex2otf.h - Header file for hex2otf.c
const NamePair defaultNames[]
Allocate array of NameID codes with default values.
Generic data structure for a linked list of buffer elements.
Data structure to hold information for one font.
Data structure to hold data for one bitmap glyph.
uint_least32_t codePoint
undefined for glyph 0
pixels_t lsb
left side bearing (x position of leftmost contour point)
uint_least8_t byteCount
length of bitmap data
byte bitmap[GLYPH_MAX_BYTE_COUNT]
hexadecimal bitmap character array
bool combining
whether this is a combining glyph
Data structure for a font ID number and name character string.
Data structure to hold options for OpenType font output.
Data structure for an OpenType table.
Data structure for data associated with one OpenType table.