Organized the HVIF module a bit more
Getty Ritter
9 years ago
| 1 | 1 | {-# LANGUAGE RecordWildCards #-} |
| 2 | 2 | |
| 3 |
module Graphics.HVIF |
|
| 3 | module Graphics.HVIF | |
| 4 | ( | |
| 5 | -- * Decoding | |
| 6 | decodeFile | |
| 7 | -- * Types | |
| 8 | , HVIFFile(..) | |
| 9 | -- ** Style Section | |
| 10 | , Style(..) | |
| 11 | , Gradient(..) | |
| 12 | , GradientType(..) | |
| 13 | , GradientFlags(..) | |
| 14 | , GradientStop(..) | |
| 15 | -- ** Paths Section | |
| 16 | , Path(..) | |
| 17 | , PathFlags(..) | |
| 18 | , Point(..) | |
| 19 | , Command(..) | |
| 20 | -- ** Shape Section | |
| 21 | , Shape(..) | |
| 22 | , PathRef(..) | |
| 23 | , StyleRef(..) | |
| 24 | , ShapeFlags(..) | |
| 25 | ) where | |
| 4 | 26 | |
| 5 | 27 | import Control.Monad (replicateM, when) |
| 6 | 28 | import Data.Bits ((.|.), (.&.), clearBit, shift, testBit) |
| 7 | 29 | import Data.ByteString (ByteString) |
| 8 |
import Data.Sequence (Seq |
|
| 30 | import Data.Sequence (Seq, (<|)) | |
| 9 | 31 | import qualified Data.Sequence as S |
| 10 | 32 | import Data.Serialize |
| 11 | 33 | import Data.Word |
| 18 | 40 | |
| 19 | 41 | decodeFile :: ByteString -> Either String HVIFFile |
| 20 | 42 | decodeFile = runGet pFile |
| 43 | ||
| 44 | instance Serialize HVIFFile where | |
| 45 | get = pFile | |
| 46 | put = error "[unfinished]" | |
| 47 | ||
| 48 | -- Style Section | |
| 49 | ||
| 50 | data Style | |
| 51 | = ColorSolid Word8 Word8 Word8 Word8 | |
| 52 | | ColorGradient Gradient | |
| 53 | | ColorSolidNoAlpha Word8 Word8 Word8 | |
| 54 | | ColorSolidGray Word8 Word8 | |
| 55 | | ColorSolidGrayNoAlpha Word8 | |
| 56 | deriving (Eq, Show) | |
| 57 | ||
| 58 | data Gradient = Gradient | |
| 59 | { gType :: GradientType | |
| 60 | , gFlags :: GradientFlags | |
| 61 | , gStops :: Seq GradientStop | |
| 62 | } deriving (Eq, Show) | |
| 63 | ||
| 64 | data GradientType | |
| 65 | = GTLinear | |
| 66 | | GTCircular | |
| 67 | | GTDiamond | |
| 68 | | GTConic | |
| 69 | | GTXY | |
| 70 | | GTSqrtXY | |
| 71 | deriving (Eq, Show) | |
| 72 | ||
| 73 | data GradientFlags = GradientFlags | |
| 74 | { gfTransform :: Bool | |
| 75 | , gfNoAlpha :: Bool | |
| 76 | , gf16Bit :: Bool | |
| 77 | , gfGrays :: Bool | |
| 78 | } deriving (Eq, Show) | |
| 79 | ||
| 80 | data GradientStop = GradientStop | |
| 81 | { gsOffset :: Word8 | |
| 82 | , gsRed :: Word8 | |
| 83 | , gsGreen :: Word8 | |
| 84 | , gsBlue :: Word8 | |
| 85 | , gsAlpha :: Word8 | |
| 86 | } deriving (Eq, Show) | |
| 87 | ||
| 88 | -- Path Section | |
| 89 | ||
| 90 | data Path = Path | |
| 91 | { pathFlags :: PathFlags | |
| 92 | , pathPoints :: Seq Command | |
| 93 | } deriving (Eq, Show) | |
| 94 | ||
| 95 | data PathFlags = PathFlags | |
| 96 | { pfClosed :: Bool | |
| 97 | , pfUsesCommands :: Bool | |
| 98 | , pfNoCurves :: Bool | |
| 99 | } deriving (Eq, Show) | |
| 100 | ||
| 101 | data Point = Point | |
| 102 | { coordX :: Float | |
| 103 | , coordY :: Float | |
| 104 | } deriving (Eq, Show) | |
| 105 | ||
| 106 | data Command | |
| 107 | = CmdHLine Float | |
| 108 | | CmdVLine Float | |
| 109 | | CmdLine Point | |
| 110 | | CmdCurve Point Point Point | |
| 111 | deriving (Eq, Show) | |
| 112 | ||
| 113 | -- Shape Section | |
| 114 | ||
| 115 | data Shape = Shape | |
| 116 | { shapeStyle :: StyleRef | |
| 117 | , shapePaths :: Seq PathRef | |
| 118 | , shapeFlags :: ShapeFlags | |
| 119 | , shapeTransform :: Maybe Matrix | |
| 120 | } deriving (Eq, Show) | |
| 121 | ||
| 122 | type Matrix = Seq Float | |
| 123 | ||
| 124 | newtype PathRef = PathRef { prIdx :: Word8 } deriving (Eq, Show) | |
| 125 | newtype StyleRef = StyleRef { stIdx :: Word8 } deriving (Eq, Show) | |
| 126 | ||
| 127 | data ShapeFlags = ShapeFlags | |
| 128 | { sfTransform :: Bool | |
| 129 | , sfHinting :: Bool | |
| 130 | , sfLodScale :: Bool | |
| 131 | , sfHasTransformers :: Bool | |
| 132 | , sfTranslation :: Bool | |
| 133 | } deriving (Eq, Show) | |
| 134 | ||
| 135 | -- Decoding code | |
| 21 | 136 | |
| 22 | 137 | getSeveral :: Get a -> Get (Seq a) |
| 23 | 138 | getSeveral getter = do |
| 34 | 149 | hvifShapes <- getSeveral pShape |
| 35 | 150 | return HVIFFile { .. } |
| 36 | 151 | |
| 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) | |
| 152 | -- Style section | |
| 46 | 153 | |
| 47 | 154 | pStyle :: Get Style |
| 48 | 155 | pStyle = do |
| 55 | 162 | 0x05 -> ColorSolidGrayNoAlpha <$> get |
| 56 | 163 | _ -> fail "invalid" |
| 57 | 164 | |
| 58 | ||
| 59 | data Gradient = Gradient | |
| 60 | { gType :: GradientType | |
| 61 | , gFlags :: GradientFlags | |
| 62 | , gStops :: Seq GradientStop | |
| 63 | } deriving (Eq, Show) | |
| 64 | ||
| 65 | 165 | pGradient :: Get Gradient |
| 66 | 166 | pGradient = do |
| 67 | 167 | gType <- pGradientType |
| 68 | 168 | gFlags <- pGradientFlags |
| 69 | 169 | gStops <- getSeveral (pGradientStop gFlags) |
| 70 | 170 | return Gradient { .. } |
| 71 | ||
| 72 | data GradientType | |
| 73 | = GTLinear | |
| 74 | | GTCircular | |
| 75 | | GTDiamond | |
| 76 | | GTConic | |
| 77 | | GTXY | |
| 78 | | GTSqrtXY | |
| 79 | deriving (Eq, Show) | |
| 80 | 171 | |
| 81 | 172 | pGradientType :: Get GradientType |
| 82 | 173 | pGradientType = do |
| 90 | 181 | 05 -> return GTSqrtXY |
| 91 | 182 | _ -> fail ("Unknown gradient type: " ++ show gType) |
| 92 | 183 | |
| 93 | ||
| 94 | data GradientFlags = GradientFlags | |
| 95 | { gfTransform :: Bool | |
| 96 | , gfNoAlpha :: Bool | |
| 97 | , gf16Bit :: Bool | |
| 98 | , gfGrays :: Bool | |
| 99 | } deriving (Eq, Show) | |
| 100 | ||
| 101 | 184 | pGradientFlags :: Get GradientFlags |
| 102 | 185 | pGradientFlags = do |
| 103 | 186 | gFlags <- getWord8 |
| 107 | 190 | , gf16Bit = testBit gFlags 3 |
| 108 | 191 | , gfGrays = testBit gFlags 4 |
| 109 | 192 | } |
| 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 | 193 | |
| 119 | 194 | pGradientStop :: GradientFlags -> Get GradientStop |
| 120 | 195 | pGradientStop flags = do |
| 135 | 210 | else get |
| 136 | 211 | return $ GradientStop offset r g b a |
| 137 | 212 | |
| 138 | ||
| 139 | 213 | -- Path Section |
| 140 | ||
| 141 | data Path = Path | |
| 142 | { pathFlags :: PathFlags | |
| 143 | , pathPoints :: Seq Command | |
| 144 | } deriving (Eq, Show) | |
| 145 | 214 | |
| 146 | 215 | pPath :: Get Path |
| 147 | 216 | pPath = do |
| 148 | 217 | pathFlags <- pPathFlags |
| 149 | 218 | pathPoints <- pPoints pathFlags |
| 150 | 219 | return Path { .. } |
| 151 | ||
| 152 | data PathFlags = PathFlags | |
| 153 | { pfClosed :: Bool | |
| 154 | , pfUsesCommands :: Bool | |
| 155 | , pfNoCurves :: Bool | |
| 156 | } deriving (Eq, Show) | |
| 157 | 220 | |
| 158 | 221 | pPathFlags :: Get PathFlags |
| 159 | 222 | pPathFlags = do |
| 163 | 226 | , pfUsesCommands = testBit pFlags 2 |
| 164 | 227 | , pfNoCurves = testBit pFlags 3 |
| 165 | 228 | } |
| 166 | ||
| 167 | data Point = Point | |
| 168 | { coordX :: Float | |
| 169 | , coordY :: Float | |
| 170 | } deriving (Eq, Show) | |
| 171 | ||
| 172 | data Command | |
| 173 | = CmdHLine Float | |
| 174 | | CmdVLine Float | |
| 175 | | CmdLine Point | |
| 176 | | CmdCurve Point Point Point | |
| 177 | deriving (Eq, Show) | |
| 178 | 229 | |
| 179 | 230 | pPoints :: PathFlags -> Get (Seq Command) |
| 180 | 231 | pPoints PathFlags { pfUsesCommands = False |
| 206 | 257 | iIdx = (n `mod` 4) * 2 |
| 207 | 258 | in case (cmdBytes !! bIdx) `shift` (negate iIdx) .&. 0x03 of |
| 208 | 259 | 0x00 -> |
| 209 |
( |
|
| 260 | (<|) <$> (CmdHLine <$> pCoord) <*> go (n+1) | |
| 210 | 261 | 0x01 -> |
| 211 |
( |
|
| 262 | (<|) <$> (CmdVLine <$> pCoord) <*> go (n+1) | |
| 212 | 263 | 0x02 -> |
| 213 |
( |
|
| 264 | (<|) <$> pLineCommand <*> go (n+1) | |
| 214 | 265 | 0x03 -> |
| 215 |
( |
|
| 266 | (<|) <$> pCurveCommand <*> go (n+1) | |
| 216 | 267 | _ -> error "[unreachable]" |
| 217 | 268 | go 0 |
| 218 | 269 | |
| 225 | 276 | return (fromIntegral cVal / 102.0 - 128.0) |
| 226 | 277 | else |
| 227 | 278 | return (fromIntegral b1 - 32.0) |
| 228 | ||
| 229 | -- Shape Section | |
| 230 | ||
| 231 | data Shape = Shape | |
| 232 | { shapeStyle :: StyleRef | |
| 233 | , shapePaths :: Seq PathRef | |
| 234 | , shapeFlags :: ShapeFlags | |
| 235 | , shapeTransform :: Maybe Matrix | |
| 236 | } deriving (Eq, Show) | |
| 237 | ||
| 238 | type Matrix = Seq Float | |
| 239 | 279 | |
| 240 | 280 | pShape :: Get Shape |
| 241 | 281 | pShape = do |
| 251 | 291 | else return Nothing |
| 252 | 292 | return Shape { .. } |
| 253 | 293 | |
| 254 | newtype PathRef = PathRef { prIdx :: Word8 } deriving (Eq, Show) | |
| 255 | newtype StyleRef = StyleRef { stIdx :: Word8 } deriving (Eq, Show) | |
| 256 | ||
| 257 | data ShapeFlags = ShapeFlags | |
| 258 | { sfTransform :: Bool | |
| 259 | , sfHinting :: Bool | |
| 260 | , sfLodScale :: Bool | |
| 261 | , sfHasTransformers :: Bool | |
| 262 | , sfTranslation :: Bool | |
| 263 | } deriving (Eq, Show) | |
| 264 | ||
| 265 | 294 | pShapeFlags :: Get ShapeFlags |
| 266 | 295 | pShapeFlags = do |
| 267 | 296 | sFlags <- getWord8 |
| 276 | 305 | pMatrix :: Get Matrix |
| 277 | 306 | pMatrix = S.fromList `fmap` replicateM 6 pFloat |
| 278 | 307 | |
| 308 | -- XXX Actually parse 24-bit floats right | |
| 279 | 309 | pFloat :: Get Float |
| 280 | 310 | pFloat = do |
| 281 | 311 | _ <- getWord8 |