From a46a9ebf1284c5c14141a3f569db5ef98b54a0dd Mon Sep 17 00:00:00 2001 From: treeform Date: Sun, 15 May 2022 12:05:17 -0700 Subject: [PATCH] api changes, encoding fixed. --- src/pixie/fontformats/opentype.nim | 29 ++++++++++++----- src/pixie/fonts.nim | 21 +++++++++---- tests/test_fonts.nim | 50 ++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/pixie/fontformats/opentype.nim b/src/pixie/fontformats/opentype.nim index f9d1e34..c151a96 100644 --- a/src/pixie/fontformats/opentype.nim +++ b/src/pixie/fontformats/opentype.nim @@ -430,16 +430,21 @@ proc readVersion16Dot16(buf: string, offset: int): float32 = failUnsupported("invalid version format") majorDigit.float32 + minorDigit.float32 / 10 -proc convertUTF16(input: string): string = +func maybeSwap(u: uint16, swap: bool): uint16 = + if swap: + ((u and 0xFF) shl 8) or ((u and 0xFF00) shr 8) + else: + u + +proc fromUTF16Inner(input: string, i: var int, swap: bool): string = ## Converts UTF16 Big Endian to UTF8 string. - var i = 0 - while i < input.len: - var u1 = input.readUInt16(i) + while i + 1 < input.len: + var u1 = input.readUInt16(i).maybeSwap(swap) i += 2 if u1 - 0xd800 >= 0x800: result.add Rune(u1.int) else: - var u2 = input.readUInt16(i) + var u2 = input.readUInt16(i).maybeSwap(swap) i += 2 if ((u1 and 0xfc00) == 0xd800) and ((u2 and 0xfc00) == 0xdc00): result.add Rune((u1.uint32 shl 10) + u2.uint32 - 0x35fdc00) @@ -447,6 +452,11 @@ proc convertUTF16(input: string): string = # Error, produce tofu character. result.add "□" +proc fromUTF16BE*(input: string): string = + ## Converts UTF16 Big Endian to UTF8 string. + var i = 0 + input.fromUTF16Inner(i, true) + proc parseCmapTable(buf: string, offset: int): CmapTable = var i = offset buf.eofCheck(i + 4) @@ -677,8 +687,11 @@ proc parseNameTable(buf: string, offset: int): NameTable = (offset + result.stringOffset.int + record.offset.int) ..< (offset + result.stringOffset.int + record.offset.int + record.length.int) ] - if record.encodingID in {1, 3}: - record.text = convertUTF16(record.text) + if record.platformID == 3 and + record.encodingID == 1 and + record.languageID == 1033: + record.text = fromUTF16BE(record.text) + record.text = record.text result.nameRecords.add(record) i += 12 @@ -2500,7 +2513,7 @@ proc fullName*(opentype: OpenType): string = if opentype.cff != nil: return opentype.cff.topDict.fullName for record in opentype.name.nameRecords: - if record.nameID == 1: + if record.nameID == 6 and record.languageID == 1033: return record.text proc parseOpenType*(buf: string, startLoc = 0): OpenType {.raises: [PixieError].} = diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index 363f3d9..d6485d7 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -496,10 +496,6 @@ proc parseOtf*(buf: string): Typeface {.raises: [PixieError].} = proc parseTtf*(buf: string): Typeface {.raises: [PixieError].} = parseOtf(buf) -proc parseTtc*(buf: string): Typeface {.raises: [PixieError].} = - result = Typeface() - result.opentype = parseOpenTypeCollection(buf)[0] - proc parseSvgFont*(buf: string): Typeface {.raises: [PixieError].} = result = Typeface() result.svgFont = svgfont.parseSvgFont(buf) @@ -701,8 +697,6 @@ proc readTypeface*(filePath: string): Typeface {.raises: [PixieError].} = parseTtf(readFile(filePath)) of ".otf": parseOtf(readFile(filePath)) - of ".ttc": - parseTtc(readFile(filePath)) of ".svg": parseSvgFont(readFile(filePath)) else: @@ -712,6 +706,21 @@ proc readTypeface*(filePath: string): Typeface {.raises: [PixieError].} = result.filePath = filePath +proc readTypefaces*(filePath: string): seq[Typeface] {.raises: [PixieError].} = + ## Loads a OpenType Collection (.ttc). + try: + for opentype in parseOpenTypeCollection(readFile(filePath)): + let typeface = Typeface() + typeface.opentype = opentype + result.add(typeface) + except IOError as e: + raise newException(PixieError, e.msg, e) + +proc name*(typeface: Typeface): string = + ## Returns the name of the font. + if typeface.opentype != nil: + return typeface.opentype.fullName + proc readFont*(filePath: string): Font {.raises: [PixieError].} = ## Loads a font from a file. newFont(readTypeface(filePath)) diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index 00f33f3..facd200 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -1196,3 +1196,53 @@ block: ) doDiff(image, "customlineheight") + +block: + var font = readTypefaces("tests/fonts/PTSans.ttc")[0].newFont + font.size = 72 + let image = newImage(200, 100) + image.fill(rgba(255, 255, 255, 255)) + image.fillText(font, "AbCd") + +block: + var typefaces = readTypefaces("tests/fonts/PTSans.ttc") + for i, typeface in typefaces: + echo i, ": ", typeface.name + +when defined(windows): + block: + let files = @[ + "/Windows/Fonts/batang.ttc", + "/Windows/Fonts/BIZ-UDGothicB.ttc", + "/Windows/Fonts/BIZ-UDGothicR.ttc", + "/Windows/Fonts/BIZ-UDMinchoM.ttc", + "/Windows/Fonts/cambria.ttc", + "/Windows/Fonts/gulim.ttc", + "/Windows/Fonts/meiryo.ttc", + "/Windows/Fonts/meiryob.ttc", + "/Windows/Fonts/mingliub.ttc", + "/Windows/Fonts/msgothic.ttc", + "/Windows/Fonts/msjh.ttc", + "/Windows/Fonts/msjhbd.ttc", + "/Windows/Fonts/msjhl.ttc", + "/Windows/Fonts/msmincho.ttc", + "/Windows/Fonts/msyh.ttc", + "/Windows/Fonts/msyhbd.ttc", + "/Windows/Fonts/msyhl.ttc", + "/Windows/Fonts/simsun.ttc", + "/Windows/Fonts/Sitka.ttc", + "/Windows/Fonts/SitkaB.ttc", + "/Windows/Fonts/SitkaI.ttc", + "/Windows/Fonts/SitkaZ.ttc", + "/Windows/Fonts/UDDigiKyokashoN-B.ttc", + "/Windows/Fonts/UDDigiKyokashoN-R.ttc", + "/Windows/Fonts/YuGothB.ttc", + "/Windows/Fonts/YuGothL.ttc", + "/Windows/Fonts/YuGothM.ttc", + "/Windows/Fonts/YuGothR.ttc", + ] + for file in files: + echo file + var typefaces = readTypefaces(file) + for i, typeface in typefaces: + echo i, ": ", typeface.name