HVIF.hs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. {-# LANGUAGE RecordWildCards #-}
  2. module Graphics.HVIF where
  3. import Control.Monad (replicateM, when)
  4. import Data.Bits ((.|.), (.&.), clearBit, shift, testBit)
  5. import Data.ByteString (ByteString)
  6. import Data.Sequence (Seq)
  7. import qualified Data.Sequence as S
  8. import Data.Serialize
  9. import Data.Word
  10. data HVIFFile = HVIFFile
  11. { hvifColors :: Seq Style
  12. , hvifPaths :: Seq Path
  13. , hvifShapes :: Seq Shape
  14. } deriving (Eq, Show)
  15. decodeFile :: ByteString -> Either String HVIFFile
  16. decodeFile = runGet pFile
  17. getSeveral :: Get a -> Get (Seq a)
  18. getSeveral getter = do
  19. count <- getWord8
  20. S.fromList `fmap` replicateM (fromIntegral count) getter
  21. pFile :: Get HVIFFile
  22. pFile = do
  23. header <- getByteString 4
  24. when (header /= "ncif") $
  25. fail "Missing `ficn' header"
  26. hvifColors <- getSeveral pStyle
  27. hvifPaths <- getSeveral pPath
  28. hvifShapes <- getSeveral pShape
  29. return HVIFFile { .. }
  30. -- Style Section
  31. data Style
  32. = ColorSolid Word8 Word8 Word8 Word8
  33. | ColorGradient Gradient
  34. | ColorSolidNoAlpha Word8 Word8 Word8
  35. | ColorSolidGray Word8 Word8
  36. | ColorSolidGrayNoAlpha Word8
  37. deriving (Eq, Show)
  38. pStyle :: Get Style
  39. pStyle = do
  40. sType <- getWord8
  41. case sType of
  42. 0x01 -> ColorSolid <$> get <*> get <*> get <*> get
  43. 0x02 -> ColorGradient <$> pGradient
  44. 0x03 -> ColorSolidNoAlpha <$> get <*> get <*> get
  45. 0x04 -> ColorSolidGray <$> get <*> get
  46. 0x05 -> ColorSolidGrayNoAlpha <$> get
  47. _ -> fail "invalid"
  48. data Gradient = Gradient
  49. { gType :: GradientType
  50. , gFlags :: GradientFlags
  51. , gStops :: Seq GradientStop
  52. } deriving (Eq, Show)
  53. pGradient :: Get Gradient
  54. pGradient = do
  55. gType <- pGradientType
  56. gFlags <- pGradientFlags
  57. gStops <- getSeveral (pGradientStop gFlags)
  58. return Gradient { .. }
  59. data GradientType
  60. = GTLinear
  61. | GTCircular
  62. | GTDiamond
  63. | GTConic
  64. | GTXY
  65. | GTSqrtXY
  66. deriving (Eq, Show)
  67. pGradientType :: Get GradientType
  68. pGradientType = do
  69. gType <- getWord8
  70. case gType of
  71. 00 -> return GTLinear
  72. 01 -> return GTCircular
  73. 02 -> return GTDiamond
  74. 03 -> return GTConic
  75. 04 -> return GTXY
  76. 05 -> return GTSqrtXY
  77. _ -> fail ("Unknown gradient type: " ++ show gType)
  78. data GradientFlags = GradientFlags
  79. { gfTransform :: Bool
  80. , gfNoAlpha :: Bool
  81. , gf16Bit :: Bool
  82. , gfGrays :: Bool
  83. } deriving (Eq, Show)
  84. pGradientFlags :: Get GradientFlags
  85. pGradientFlags = do
  86. gFlags <- getWord8
  87. return $ GradientFlags
  88. { gfTransform = testBit gFlags 1
  89. , gfNoAlpha = testBit gFlags 2
  90. , gf16Bit = testBit gFlags 3
  91. , gfGrays = testBit gFlags 4
  92. }
  93. data GradientStop = GradientStop
  94. { gsOffset :: Word8
  95. , gsRed :: Word8
  96. , gsGreen :: Word8
  97. , gsBlue :: Word8
  98. , gsAlpha :: Word8
  99. } deriving (Eq, Show)
  100. pGradientStop :: GradientFlags -> Get GradientStop
  101. pGradientStop flags = do
  102. offset <- get
  103. (r, g, b) <-
  104. if gfGrays flags
  105. then do
  106. val <- get
  107. return (val, val, val)
  108. else do
  109. r <- get
  110. g <- get
  111. b <- get
  112. return (r, g, b)
  113. a <-
  114. if gfNoAlpha flags
  115. then return 0xff
  116. else get
  117. return $ GradientStop offset r g b a
  118. -- Path Section
  119. data Path = Path
  120. { pathFlags :: PathFlags
  121. , pathPoints :: Seq Command
  122. } deriving (Eq, Show)
  123. pPath :: Get Path
  124. pPath = do
  125. pathFlags <- pPathFlags
  126. pathPoints <- pPoints pathFlags
  127. return Path { .. }
  128. data PathFlags = PathFlags
  129. { pfClosed :: Bool
  130. , pfUsesCommands :: Bool
  131. , pfNoCurves :: Bool
  132. } deriving (Eq, Show)
  133. pPathFlags :: Get PathFlags
  134. pPathFlags = do
  135. pFlags <- getWord8
  136. return $ PathFlags
  137. { pfClosed = testBit pFlags 1
  138. , pfUsesCommands = testBit pFlags 2
  139. , pfNoCurves = testBit pFlags 3
  140. }
  141. data Point = Point
  142. { coordX :: Float
  143. , coordY :: Float
  144. } deriving (Eq, Show)
  145. data Command
  146. = CmdHLine Float
  147. | CmdVLine Float
  148. | CmdLine Point
  149. | CmdCurve Point Point Point
  150. deriving (Eq, Show)
  151. pPoints :: PathFlags -> Get (Seq Command)
  152. pPoints PathFlags { pfUsesCommands = False
  153. , pfNoCurves = False } =
  154. getSeveral pCurveCommand
  155. pPoints PathFlags { pfUsesCommands = False
  156. , pfNoCurves = True } =
  157. getSeveral pLineCommand
  158. pPoints PathFlags { pfUsesCommands = True } =
  159. pCommandList
  160. pLineCommand :: Get Command
  161. pLineCommand = CmdLine <$> (Point <$> pCoord <*> pCoord)
  162. pCurveCommand :: Get Command
  163. pCurveCommand = CmdCurve <$> (Point <$> pCoord <*> pCoord)
  164. <*> (Point <$> pCoord <*> pCoord)
  165. <*> (Point <$> pCoord <*> pCoord)
  166. pCommandList :: Get (Seq Command)
  167. pCommandList = do
  168. pointCount <- getWord8
  169. let cmdByteCount = (pointCount + 3) `div` 4
  170. cmdBytes <- replicateM (fromIntegral cmdByteCount) getWord8
  171. let go n
  172. | n == fromIntegral pointCount = return S.empty
  173. | otherwise =
  174. let bIdx = n `div` 4
  175. iIdx = (n `mod` 4) * 2
  176. in case (cmdBytes !! bIdx) `shift` (negate iIdx) .&. 0x03 of
  177. 0x00 ->
  178. (S.<|) <$> (CmdHLine <$> pCoord) <*> go (n+1)
  179. 0x01 ->
  180. (S.<|) <$> (CmdVLine <$> pCoord) <*> go (n+1)
  181. 0x02 ->
  182. (S.<|) <$> pLineCommand <*> go (n+1)
  183. 0x03 ->
  184. (S.<|) <$> pCurveCommand <*> go (n+1)
  185. _ -> error "[unreachable]"
  186. go 0
  187. pCoord :: Get Float
  188. pCoord = do
  189. b1 <- getWord8
  190. if testBit b1 7 then do
  191. b2 <- getWord8
  192. let cVal :: Word16 = (clearBit (fromIntegral b1) 7 `shift` 8) .|. fromIntegral b2
  193. return (fromIntegral cVal / 102.0 - 128.0)
  194. else
  195. return (fromIntegral b1 - 32.0)
  196. -- Shape Section
  197. data Shape = Shape
  198. { shapeStyle :: StyleRef
  199. , shapePaths :: Seq PathRef
  200. , shapeFlags :: ShapeFlags
  201. , shapeTransform :: Maybe Matrix
  202. } deriving (Eq, Show)
  203. type Matrix = Seq Float
  204. pShape :: Get Shape
  205. pShape = do
  206. sType <- getWord8
  207. when (sType /= 0x0a) $
  208. fail ("Unknown shape type: " ++ show sType)
  209. shapeStyle <- StyleRef <$> get
  210. shapePaths <- getSeveral (PathRef <$> get)
  211. shapeFlags <- pShapeFlags
  212. shapeTransform <-
  213. if sfTransform shapeFlags
  214. then Just <$> pMatrix
  215. else return Nothing
  216. return Shape { .. }
  217. newtype PathRef = PathRef { prIdx :: Word8 } deriving (Eq, Show)
  218. newtype StyleRef = StyleRef { stIdx :: Word8 } deriving (Eq, Show)
  219. data ShapeFlags = ShapeFlags
  220. { sfTransform :: Bool
  221. , sfHinting :: Bool
  222. , sfLodScale :: Bool
  223. , sfHasTransformers :: Bool
  224. , sfTranslation :: Bool
  225. } deriving (Eq, Show)
  226. pShapeFlags :: Get ShapeFlags
  227. pShapeFlags = do
  228. sFlags <- getWord8
  229. return ShapeFlags
  230. { sfTransform = testBit sFlags 1
  231. , sfHinting = testBit sFlags 2
  232. , sfLodScale = testBit sFlags 3
  233. , sfHasTransformers = testBit sFlags 4
  234. , sfTranslation = testBit sFlags 5
  235. }
  236. pMatrix :: Get Matrix
  237. pMatrix = S.fromList `fmap` replicateM 6 pFloat
  238. pFloat :: Get Float
  239. pFloat = do
  240. _ <- getWord8
  241. _ <- getWord8
  242. _ <- getWord8
  243. return 0.0