gdritter repos hvif / 99d3538
Unfinished HVIF types + decoder Getty Ritter 7 years ago
3 changed file(s) with 251 addition(s) and 0 deletion(s). Collapse all Expand all
1 dist
2 dist-newstyle
3 *~
1 {-# LANGUAGE RecordWildCards #-}
2
3 module Graphics.HVIF where
4
5 import Control.Monad (replicateM, when)
6 import Data.Bits ((.|.), clearBit, shift, testBit)
7 import Data.ByteString (ByteString)
8 import Data.Sequence (Seq)
9 import qualified Data.Sequence as S
10 import Data.Serialize
11 import Data.Word
12
13 data HVIFFile = HVIFFile
14 { hvifColors :: Seq Style
15 , hvifPaths :: Seq Path
16 , hvifShapes :: Seq Shape
17 } deriving (Eq, Show)
18
19 decodeFile :: ByteString -> Either String HVIFFile
20 decodeFile = runGet pFile
21
22 getSeveral :: Get a -> Get (Seq a)
23 getSeveral getter = do
24 count <- getWord8
25 S.fromList `fmap` replicateM (fromIntegral count) getter
26
27 pFile :: Get HVIFFile
28 pFile = do
29 header <- getByteString 4
30 when (header /= "ncif") $
31 fail "Missing `ficn' header"
32 hvifColors <- getSeveral pStyle
33 hvifPaths <- getSeveral pPath
34 hvifShapes <- getSeveral pShape
35 return HVIFFile { .. }
36
37 -- Style Section
38
39 data Style
40 = ColorSolid Word8 Word8 Word8 Word8
41 | ColorGradient Gradient
42 | ColorSolidNoAlpha Word8 Word8 Word8
43 | ColorSolidGray Word8 Word8
44 | ColorSolidGrayNoAlpha Word8
45 deriving (Eq, Show)
46
47 pStyle :: Get Style
48 pStyle = do
49 sType <- getWord8
50 case sType of
51 0x01 -> ColorSolid <$> get <*> get <*> get <*> get
52 0x02 -> ColorGradient <$> pGradient
53 0x03 -> ColorSolidNoAlpha <$> get <*> get <*> get
54 0x04 -> ColorSolidGray <$> get <*> get
55 0x05 -> ColorSolidGrayNoAlpha <$> get
56 _ -> fail "invalid"
57
58
59 data Gradient = Gradient
60 { gType :: GradientType
61 , gFlags :: GradientFlags
62 , gStops :: Seq GradientStop
63 } deriving (Eq, Show)
64
65 pGradient :: Get Gradient
66 pGradient = do
67 gType <- pGradientType
68 gFlags <- pGradientFlags
69 gStops <- getSeveral (pGradientStop gFlags)
70 return Gradient { .. }
71
72 data GradientType
73 = GTLinear
74 | GTCircular
75 | GTDiamond
76 | GTConic
77 | GTXY
78 | GTSqrtXY
79 deriving (Eq, Show)
80
81 pGradientType :: Get GradientType
82 pGradientType = do
83 gType <- getWord8
84 case gType of
85 00 -> return GTLinear
86 01 -> return GTCircular
87 02 -> return GTDiamond
88 03 -> return GTConic
89 04 -> return GTXY
90 05 -> return GTSqrtXY
91 _ -> fail ("Unknown gradient type: " ++ show gType)
92
93
94 data GradientFlags = GradientFlags
95 { gfTransform :: Bool
96 , gfNoAlpha :: Bool
97 , gf16Bit :: Bool
98 , gfGrays :: Bool
99 } deriving (Eq, Show)
100
101 pGradientFlags :: Get GradientFlags
102 pGradientFlags = do
103 gFlags <- getWord8
104 return $ GradientFlags
105 { gfTransform = testBit gFlags 1
106 , gfNoAlpha = testBit gFlags 2
107 , gf16Bit = testBit gFlags 3
108 , gfGrays = testBit gFlags 4
109 }
110
111 data GradientStop = GradientStop
112 { gsOffset :: Word8
113 , gsRed :: Word8
114 , gsGreen :: Word8
115 , gsBlue :: Word8
116 , gsAlpha :: Word8
117 } deriving (Eq, Show)
118
119 pGradientStop :: GradientFlags -> Get GradientStop
120 pGradientStop flags = do
121 offset <- get
122 (r, g, b) <-
123 if gfGrays flags
124 then do
125 val <- get
126 return (val, val, val)
127 else do
128 r <- get
129 g <- get
130 b <- get
131 return (r, g, b)
132 a <-
133 if gfNoAlpha flags
134 then return 0xff
135 else get
136 return $ GradientStop offset r g b a
137
138
139 -- Path Section
140
141 data Path = Path
142 { pathFlags :: PathFlags
143 , pathPoints :: Seq Point
144 } deriving (Eq, Show)
145
146 pPath :: Get Path
147 pPath = do
148 pathFlags <- pPathFlags
149 pathPoints <- pPoints pathFlags
150 return Path { .. }
151
152 data PathFlags = PathFlags
153 { pfClosed :: Bool
154 , pfUsesCommands :: Bool
155 , pfNoCurves :: Bool
156 } deriving (Eq, Show)
157
158 pPathFlags :: Get PathFlags
159 pPathFlags = do
160 pFlags <- getWord8
161 return $ PathFlags
162 { pfClosed = testBit pFlags 1
163 , pfUsesCommands = testBit pFlags 2
164 , pfNoCurves = testBit pFlags 3
165 }
166
167 data Point = Point
168 { coordX :: Float
169 , coordY :: Float
170 } deriving (Eq, Show)
171
172 pPoints :: PathFlags -> Get (Seq Point)
173 pPoints PathFlags { pfUsesCommands = False } =
174 getSeveral (Point <$> pCoord <*> pCoord)
175 pPoints PathFlags { pfUsesCommands = True } = do
176 c1 <- getWord8
177 c2 <- getWord8
178 return $ S.empty
179
180 pCoord :: Get Float
181 pCoord = do
182 b1 <- getWord8
183 if testBit b1 7 then do
184 b2 <- getWord8
185 let cVal :: Word16 = (clearBit 7 (fromIntegral b1) `shift` 8) .|. fromIntegral b2
186 return ((fromIntegral cVal / 102.0) - 128.0)
187 else
188 return (fromIntegral b1 - 32.0)
189
190 -- Shape Section
191
192 data Shape = Shape
193 { shapeStyle :: StyleRef
194 , shapePaths :: Seq PathRef
195 , shapeFlags :: ShapeFlags
196 } deriving (Eq, Show)
197
198 pShape :: Get Shape
199 pShape = do
200 shapeStyle <- StyleRef <$> get
201 shapePaths <- getSeveral (PathRef <$> get)
202 shapeFlags <- pShapeFlags
203 return Shape { .. }
204
205 newtype PathRef = PathRef { prIdx :: Word8 } deriving (Eq, Show)
206 newtype StyleRef = StyleRef { stIdx :: Word8 } deriving (Eq, Show)
207
208 data ShapeFlags = ShapeFlags
209 { sfTransform :: Bool
210 , sfHinting :: Bool
211 , sfLodScale :: Bool
212 , sfHasTransformers :: Bool
213 , sfTranslation :: Bool
214 } deriving (Eq, Show)
215
216 pShapeFlags :: Get ShapeFlags
217 pShapeFlags = do
218 sFlags <- getWord8
219 return ShapeFlags
220 { sfTransform = testBit sFlags 1
221 , sfHinting = testBit sFlags 2
222 , sfLodScale = testBit sFlags 3
223 , sfHasTransformers = testBit sFlags 4
224 , sfTranslation = testBit sFlags 5
225 }
1 name: hvif
2 version: 0.1.0.0
3 -- synopsis:
4 -- description:
5 license: BSD3
6 license-file: LICENSE
7 author: Getty Ritter <gettylefou@gmail.com>
8 maintainer: Getty Ritter <gettylefou@gmail.com>
9 copyright: ©2016 Getty Ritter
10 -- category:
11 build-type: Simple
12 cabal-version: >= 1.12
13
14 library
15 exposed-modules: Graphics.HVIF
16 ghc-options: -Wall
17 build-depends: base >=4.7 && <4.9
18 , bytestring
19 , cereal
20 , containers
21 default-language: Haskell2010
22 default-extensions: OverloadedStrings,
23 ScopedTypeVariables