Extract metrics from the OS/2 table
This commit is contained in:
parent
41b5c14e2f
commit
ca70d648a9
@ -5,6 +5,7 @@
|
|||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
|
||||||
module Graphics.Fountainhead.Metrics
|
module Graphics.Fountainhead.Metrics
|
||||||
( FontBBox(..)
|
( FontBBox(..)
|
||||||
@ -24,9 +25,14 @@ import Graphics.Fountainhead.TrueType
|
|||||||
, HheaTable(..)
|
, HheaTable(..)
|
||||||
, NameRecord(..)
|
, NameRecord(..)
|
||||||
, NameTable(..)
|
, NameTable(..)
|
||||||
|
, Os2BaseFields(..)
|
||||||
|
, Os2Version4Fields(..)
|
||||||
|
, Os2Version5Fields(..)
|
||||||
|
, Os2Table(..)
|
||||||
, PostHeader(..)
|
, PostHeader(..)
|
||||||
, PostTable(..)
|
, PostTable(..)
|
||||||
, findTableByTag
|
, findTableByTag
|
||||||
|
, pattern Os2Version4CommonFields
|
||||||
)
|
)
|
||||||
import Graphics.Fountainhead.Parser
|
import Graphics.Fountainhead.Parser
|
||||||
( ParseErrorBundle
|
( ParseErrorBundle
|
||||||
@ -35,14 +41,14 @@ import Graphics.Fountainhead.Parser
|
|||||||
, parseTable
|
, parseTable
|
||||||
, headTableP
|
, headTableP
|
||||||
, hheaTableP
|
, hheaTableP
|
||||||
|
, os2TableP
|
||||||
, postTableP
|
, postTableP
|
||||||
)
|
)
|
||||||
import qualified Text.Megaparsec as Megaparsec
|
import qualified Text.Megaparsec as Megaparsec
|
||||||
import Data.Bifunctor (Bifunctor(..))
|
import Data.Bifunctor (Bifunctor(..))
|
||||||
import Data.Int (Int16, Int32)
|
import Data.Int (Int16)
|
||||||
import Data.Word (Word16)
|
import Data.Word (Word16)
|
||||||
import GHC.Records (HasField(..))
|
import GHC.Records (HasField(..))
|
||||||
import Graphics.Fountainhead.Type (Fixed32(..))
|
|
||||||
|
|
||||||
type Number = Float
|
type Number = Float
|
||||||
|
|
||||||
@ -99,6 +105,7 @@ data MetricsError
|
|||||||
= MetricsParseError ParseErrorBundle
|
= MetricsParseError ParseErrorBundle
|
||||||
| MetricsRequiredTableMissingError String
|
| MetricsRequiredTableMissingError String
|
||||||
| MetricsNameRecordNotFound Word16
|
| MetricsNameRecordNotFound Word16
|
||||||
|
| UnsupportedOs2VersionError
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|
||||||
instance Show MetricsError
|
instance Show MetricsError
|
||||||
@ -108,6 +115,8 @@ instance Show MetricsError
|
|||||||
"Required table " <> tableName <> " is missing."
|
"Required table " <> tableName <> " is missing."
|
||||||
show (MetricsNameRecordNotFound nameId) =
|
show (MetricsNameRecordNotFound nameId) =
|
||||||
"Name record with ID " <> show nameId <> " was not found."
|
"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 :: FilePath -> ByteString -> Either MetricsError FontDescriptor
|
||||||
collectMetrics fontFile ttfContents =
|
collectMetrics fontFile ttfContents =
|
||||||
@ -138,18 +147,32 @@ collectMetrics fontFile ttfContents =
|
|||||||
PostTable{ postHeader } <- first MetricsParseError
|
PostTable{ postHeader } <- first MetricsParseError
|
||||||
$ parseTable postEntry postTableP processedState
|
$ parseTable postEntry postTableP processedState
|
||||||
|
|
||||||
|
(capHeight, weightClass) <- getCapHeight processedState initialResult
|
||||||
|
|
||||||
pure $ FontDescriptor
|
pure $ FontDescriptor
|
||||||
{ fontName = variableText nameRecord variable psNameIndex
|
{ fontName = variableText nameRecord variable psNameIndex
|
||||||
, flags = []
|
, flags = []
|
||||||
, stemV = 1
|
, stemV = calculateStemV $ fromIntegral weightClass
|
||||||
, missingWidth = 0
|
, missingWidth = 0
|
||||||
, fontBBox = calculateBoundingBox scale headTable
|
, fontBBox = calculateBoundingBox scale headTable
|
||||||
, italicAngle = realToFrac $ getField @"italicAngle" postHeader
|
, italicAngle = realToFrac $ getField @"italicAngle" postHeader
|
||||||
, capHeight = 0
|
, capHeight = fromIntegral $ scalePs scale capHeight
|
||||||
, ascender = fromIntegral $ scalePs scale ascent
|
, ascender = fromIntegral $ scalePs scale ascent
|
||||||
, descender = fromIntegral $ scalePs scale descent
|
, descender = fromIntegral $ scalePs scale descent
|
||||||
}
|
}
|
||||||
where
|
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 } =
|
calculateBoundingBox scale HeadTable{ xMin, xMax, yMin, yMax } =
|
||||||
let xMin' = fromIntegral $ scalePs scale xMin
|
let xMin' = fromIntegral $ scalePs scale xMin
|
||||||
yMin' = fromIntegral $ scalePs scale yMin
|
yMin' = fromIntegral $ scalePs scale yMin
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE DuplicateRecordFields #-}
|
{-# LANGUAGE DuplicateRecordFields #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE PatternSynonyms #-}
|
||||||
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
|
||||||
-- | Types representing a TrueType font.
|
-- | Types representing a TrueType font.
|
||||||
module Graphics.Fountainhead.TrueType
|
module Graphics.Fountainhead.TrueType
|
||||||
@ -85,6 +88,7 @@ module Graphics.Fountainhead.TrueType
|
|||||||
, findTableByTag
|
, findTableByTag
|
||||||
, unLocaTable
|
, unLocaTable
|
||||||
, nameStringOffset
|
, nameStringOffset
|
||||||
|
, pattern Os2Version4CommonFields
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
@ -545,6 +549,21 @@ data Os2Table
|
|||||||
| Os2Version5 Os2BaseFields Os2MicrosoftFields Os2Version5Fields
|
| Os2Version5 Os2BaseFields Os2MicrosoftFields Os2Version5Fields
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
pattern Os2Version4CommonFields :: Os2BaseFields -> Os2Version4Fields -> Os2Table
|
||||||
|
pattern Os2Version4CommonFields baseFields versionFields <-
|
||||||
|
(os2Version4CommonFields -> Just (baseFields, versionFields))
|
||||||
|
|
||||||
|
{-# COMPLETE Os2Version4CommonFields, Os2Version0, Os2Version1, Os2Version5 #-}
|
||||||
|
|
||||||
|
os2Version4CommonFields :: Os2Table -> Maybe (Os2BaseFields, Os2Version4Fields)
|
||||||
|
os2Version4CommonFields = \case
|
||||||
|
Os2Version0{} -> Nothing
|
||||||
|
Os2Version1{} -> Nothing
|
||||||
|
Os2Version2 baseFields _ versionFields -> Just (baseFields, versionFields)
|
||||||
|
Os2Version3 baseFields _ versionFields -> Just (baseFields, versionFields)
|
||||||
|
Os2Version4 baseFields _ versionFields -> Just (baseFields, versionFields)
|
||||||
|
Os2Version5{} -> Nothing
|
||||||
|
|
||||||
data Os2Version1Fields = Os2Version1Fields
|
data Os2Version1Fields = Os2Version1Fields
|
||||||
{ ulCodePageRange1 :: Word32
|
{ ulCodePageRange1 :: Word32
|
||||||
, ulCodePageRange2 :: Word32
|
, ulCodePageRange2 :: Word32
|
||||||
|
Loading…
Reference in New Issue
Block a user