HVIF.hs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 Point
  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. pPoints :: PathFlags -> Get (Seq Point)
  146. pPoints PathFlags { pfUsesCommands = False } =
  147. getSeveral (Point <$> pCoord <*> pCoord)
  148. pPoints PathFlags { pfUsesCommands = True } = do
  149. c1 <- getWord8
  150. c2 <- getWord8
  151. return $ S.empty
  152. pCoord :: Get Float
  153. pCoord = do
  154. b1 <- getWord8
  155. if testBit b1 7 then do
  156. b2 <- getWord8
  157. let cVal :: Word16 = (clearBit 7 (fromIntegral b1) `shift` 8) .|. fromIntegral b2
  158. return ((fromIntegral cVal / 102.0) - 128.0)
  159. else
  160. return (fromIntegral b1 - 32.0)
  161. -- Shape Section
  162. data Shape = Shape
  163. { shapeStyle :: StyleRef
  164. , shapePaths :: Seq PathRef
  165. , shapeFlags :: ShapeFlags
  166. } deriving (Eq, Show)
  167. pShape :: Get Shape
  168. pShape = do
  169. shapeStyle <- StyleRef <$> get
  170. shapePaths <- getSeveral (PathRef <$> get)
  171. shapeFlags <- pShapeFlags
  172. return Shape { .. }
  173. newtype PathRef = PathRef { prIdx :: Word8 } deriving (Eq, Show)
  174. newtype StyleRef = StyleRef { stIdx :: Word8 } deriving (Eq, Show)
  175. data ShapeFlags = ShapeFlags
  176. { sfTransform :: Bool
  177. , sfHinting :: Bool
  178. , sfLodScale :: Bool
  179. , sfHasTransformers :: Bool
  180. , sfTranslation :: Bool
  181. } deriving (Eq, Show)
  182. pShapeFlags :: Get ShapeFlags
  183. pShapeFlags = do
  184. sFlags <- getWord8
  185. return ShapeFlags
  186. { sfTransform = testBit sFlags 1
  187. , sfHinting = testBit sFlags 2
  188. , sfLodScale = testBit sFlags 3
  189. , sfHasTransformers = testBit sFlags 4
  190. , sfTranslation = testBit sFlags 5
  191. }