Extract metrics from the OS/2 table

This commit is contained in:
2024-02-12 14:05:39 +01:00
parent 41b5c14e2f
commit ca70d648a9
2 changed files with 46 additions and 4 deletions

View File

@@ -5,6 +5,7 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE PatternSynonyms #-}
module Graphics.Fountainhead.Metrics
( FontBBox(..)
@@ -24,9 +25,14 @@ import Graphics.Fountainhead.TrueType
, HheaTable(..)
, NameRecord(..)
, NameTable(..)
, Os2BaseFields(..)
, Os2Version4Fields(..)
, Os2Version5Fields(..)
, Os2Table(..)
, PostHeader(..)
, PostTable(..)
, findTableByTag
, pattern Os2Version4CommonFields
)
import Graphics.Fountainhead.Parser
( ParseErrorBundle
@@ -35,14 +41,14 @@ import Graphics.Fountainhead.Parser
, parseTable
, headTableP
, hheaTableP
, os2TableP
, postTableP
)
import qualified Text.Megaparsec as Megaparsec
import Data.Bifunctor (Bifunctor(..))
import Data.Int (Int16, Int32)
import Data.Int (Int16)
import Data.Word (Word16)
import GHC.Records (HasField(..))
import Graphics.Fountainhead.Type (Fixed32(..))
type Number = Float
@@ -99,6 +105,7 @@ data MetricsError
= MetricsParseError ParseErrorBundle
| MetricsRequiredTableMissingError String
| MetricsNameRecordNotFound Word16
| UnsupportedOs2VersionError
deriving Eq
instance Show MetricsError
@@ -108,6 +115,8 @@ instance Show MetricsError
"Required table " <> tableName <> " is missing."
show (MetricsNameRecordNotFound nameId) =
"Name record with ID " <> show nameId <> " was not found."
show UnsupportedOs2VersionError =
"OS/2 version 1 does not contain cap height."
collectMetrics :: FilePath -> ByteString -> Either MetricsError FontDescriptor
collectMetrics fontFile ttfContents =
@@ -138,18 +147,32 @@ collectMetrics fontFile ttfContents =
PostTable{ postHeader } <- first MetricsParseError
$ parseTable postEntry postTableP processedState
(capHeight, weightClass) <- getCapHeight processedState initialResult
pure $ FontDescriptor
{ fontName = variableText nameRecord variable psNameIndex
, flags = []
, stemV = 1
, stemV = calculateStemV $ fromIntegral weightClass
, missingWidth = 0
, fontBBox = calculateBoundingBox scale headTable
, italicAngle = realToFrac $ getField @"italicAngle" postHeader
, capHeight = 0
, capHeight = fromIntegral $ scalePs scale capHeight
, ascender = fromIntegral $ scalePs scale ascent
, descender = fromIntegral $ scalePs scale descent
}
where
calculateStemV weightClass = 10 + 220 * (weightClass - 50) / 900
getCapHeight processedState initialResult = do
os2Entry <- maybeMetricsError (MetricsRequiredTableMissingError "OS/2")
$ findTableByTag "OS/2" initialResult
os2Table <- first MetricsParseError
$ parseTable os2Entry os2TableP processedState
case os2Table of
Os2Version4CommonFields Os2BaseFields{ usWeightClass } Os2Version4Fields{ sCapHeight } ->
Right (sCapHeight, usWeightClass)
Os2Version5 Os2BaseFields{ usWeightClass } _ Os2Version5Fields{ sCapHeight } ->
Right (sCapHeight, usWeightClass)
_ -> Left UnsupportedOs2VersionError
calculateBoundingBox scale HeadTable{ xMin, xMax, yMin, yMax } =
let xMin' = fromIntegral $ scalePs scale xMin
yMin' = fromIntegral $ scalePs scale yMin