Open frankrolf opened 8 years ago
Ugh, this is indeed pretty nasty.
from random import choice
fs = FormattedString()
fs.fontSize(100)
fs.lineHeight(100)
for i in range(10):
fontName = choice(installedFonts())
fs.append("Hello\n", font=fontName)
box = (100, 100, 800, 800)
fill(1, 0, 0)
prev = None
for x, y in textBoxBaselines(fs, box):
rect(0, y, width(), 1)
if prev is not None:
print(prev - y)
prev = y
fill(0)
textBox(fs, box)
what can I say... those are the values that coreText is calculating.
Well, if CoreText doesn't make sense, we'll have to make sense for it I'm afraid... This is simply no way to do typography.
textEdit.app has this exactly checkbox I dont see this reflecting in the api, like in a NSParagraphStyle
We're doing a lot of calculation anyway, so if we can implement our own exactLineHeights=True
thing somewhere (textBox()
? FormattedString
attr?), that would be great.
I know but this becomes super huge super fast: textBox
text overflow depends on line heights or what with multiple line heights in a single formatted string...
(Im hoping on some weird coreText settings to get the exact line height)
the saga continues:
this explains clearly what happens while typesetting: https://medium.com/@at_underscore/nsparagraphstyle-explained-visually-a8659d1fbd6f
but it has no effect when using multiple fonts in the same formattedString
from random import choice
fs = FormattedString()
fs.fontSize(50)
fs.lineHeight(100)
fontNames = [
"Seravek-BoldItalic",
"Times-Italic",
"AvenirNextCondensed-Italic",
"STSong",
"STIXSizeThreeSym-Regular",
"BodoniSvtyTwoOSITCTT-BookIt",
"TamilMN-Bold",
"ArialUnicodeMS",
"AvenirNextCondensed-HeavyItalic",
"MesquiteStd",
]
import AppKit
for i in range(10):
fontName = fontNames[i]
para = AppKit.NSMutableParagraphStyle.alloc().init()
para.setLineSpacing_(0)
para.setLineHeightMultiple_(0)
para.setMinimumLineHeight_(fs._lineHeight)
para.setMaximumLineHeight_(fs._lineHeight)
nsf = AppKit.NSFont.fontWithName_size_(fontName, fs._fontSize)
attributes = {
AppKit.NSFontAttributeName: nsf,
AppKit.NSForegroundColorAttributeName: AppKit.NSColor.blackColor(),
AppKit.NSParagraphStyleAttributeName: para
}
print max([para.minimumLineHeight(), min([nsf.defaultLineHeightForFont() * para.lineHeightMultiple(), para.maximumLineHeight()])]) + para.lineSpacing()
txt = AppKit.NSAttributedString.alloc().initWithString_attributes_("Hello\n", attributes)
fs._attributedString.appendAttributedString_(txt)
box = (100, 100, 800, 800)
fill(1, 0, 0)
prev = None
print
for x, y in textBoxBaselines(fs, box):
rect(0, y, width(), 1)
if prev is not None:
print(prev - y)
prev = y
fill(0)
textBox(fs, box)
fill(None)
stroke(0)
rect(*box)
next step in the line height sequel:
trying to use CTParagraphStyleCreate
as there could be a difference between a NSParagraphStyle
and a CTParagraphStyle
from random import choice
fs = FormattedString()
fs.fontSize(50)
fs.lineHeight(82)
fontNames = [
"Seravek-BoldItalic",
"Times-Italic",
"AvenirNextCondensed-Italic",
"STSong",
"STIXSizeThreeSym-Regular",
"BodoniSvtyTwoOSITCTT-BookIt",
"TamilMN-Bold",
"ArialUnicodeMS",
"AvenirNextCondensed-HeavyItalic",
"MesquiteStd",
]
import AppKit
import CoreText
import objc
import struct
for i in range(10):
fontName = fontNames[i]
linespacing = 0
minLineHeight = fs._lineHeight
maxLineheight = fs._lineHeight
lineSpaceAdjustment = -10000
para = AppKit.NSMutableParagraphStyle.alloc().init()
para.setLineSpacing_(linespacing)
para.setLineHeightMultiple_(lineSpaceAdjustment)
para.setMinimumLineHeight_(minLineHeight)
para.setMaximumLineHeight_(maxLineheight)
float_pack = "d"
settings = [
CoreText.CTParagraphStyleSetting(
spec=CoreText.kCTParagraphStyleSpecifierLineSpacing,
valueSize=CoreText.sizeof_CGFloat,
value=struct.pack(float_pack, linespacing)
),
CoreText.CTParagraphStyleSetting(
spec=CoreText.kCTParagraphStyleSpecifierMinimumLineHeight,
valueSize=CoreText.sizeof_CGFloat,
value=struct.pack(float_pack, minLineHeight)
),
CoreText.CTParagraphStyleSetting(
spec=CoreText.kCTParagraphStyleSpecifierMaximumLineHeight,
valueSize=CoreText.sizeof_CGFloat,
value=struct.pack(float_pack, maxLineheight)
),
CoreText.CTParagraphStyleSetting(
spec=CoreText.kCTParagraphStyleSpecifierLineSpacingAdjustment,
valueSize=CoreText.sizeof_CGFloat,
value=struct.pack(float_pack, lineSpaceAdjustment)
)
]
ctpara = CoreText.CTParagraphStyleCreate(settings, len(settings))
nsf = AppKit.NSFont.fontWithName_size_(fontName, fs._fontSize)
attributes = {
AppKit.NSFontAttributeName: nsf,
AppKit.NSForegroundColorAttributeName: AppKit.NSColor.blackColor(),
# use the core text paragraph style in the attributed string
CoreText.kCTParagraphStyleAttributeName: ctpara
}
print nsf.defaultLineHeightForFont(), fontName
print max([para.minimumLineHeight(), min([nsf.defaultLineHeightForFont() * para.lineHeightMultiple(), para.maximumLineHeight()])]) + para.lineSpacing()
txt = AppKit.NSAttributedString.alloc().initWithString_attributes_("Hello\n", attributes)
fs._attributedString.appendAttributedString_(txt)
print
box = (100, 100, 800, 800)
fill(1, 0, 0)
prev = None
for x, y in textBoxBaselines(fs, box):
rect(0, y, width(), 1)
if prev is not None:
print(prev - y)
prev = y
fill(0)
textBox(fs, box)
fill(None)
stroke(0)
rect(*box)
😢
I noticed that setting the line height for a formatted string will do something, but not necessarily what I expect. Especially if there is more than one font, the line heights are all different: