Question

En tant que projet pour approfondir mes connaissances et de confort avec Haskell je travaille à la mise en œuvre d'un décodeur JPEG qui sera utile pour les travaux futurs de la vision par ordinateur.

La première étape I ai choisi est d'analyser tous les « marqueurs » dans l'image. Ceux-ci sont indiquées par l'octet 0xFF suivi d'un octet non-0. Un octet 0xFF suivi d'un octet de 0x00 doit être traitée en tant que données normales.

Le problème que je suis en cours d'exécution en est que lors de la rencontre d'une combinaison 0xFF 0x00, l'analyse syntaxique semble finir complètement et ne sont trouvé plusieurs marqueurs valides (si vous exécutez sur un JPEG standard, vous verrez le début de marqueur d'image analysable, mais pas le marqueur de fin de l'image aussi souvent 0xFF 0x00 se produit dans les données d'image lui-même).

import System.Environment
import System.IO

import Control.Applicative hiding (many)
import Data.Attoparsec as A
import qualified Data.ByteString as BS

parseMarker = do
  part1 <- word8 0xFF
  part2 <- notWord8 0x0
  return (part1, part2)

parseSection = do
  A.skipWhile (\x -> x /= 0xFF) *> parseMarker

parseBody = do
  many parseSection

parseJPEG jpeg = do
  handleParseResult $ feed (parse parseBody jpeg) BS.empty

handleParseResult result = do
  case result of
    Fail _ _ msg -> msg
    Done _ r -> show r
    _ -> ""

main = do
  (filename : _ ) <- getArgs
  handle <- openFile filename ReadMode
  contents <- BS.hGetContents handle
  putStrLn $ parseJPEG contents
  hClose handle

https://gist.github.com/767488

Était-ce utile?

La solution

Depuis parseMarker consomme entrée mais peut échouer pendant l'opération, vous devez être en mesure de « revenir en arrière » et essayer de nouveau une analyse syntaxique différente lorsque vous rencontrez un 0xFF 0x00.

Je n'ai pas Attoparsec installé mais je suppose qu'il est similaire à parsec qui ne backtrack pas par défaut.

parseSection =
    skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker

Autres conseils

Le problème est que vous ne dites pas à analyser une séquence de 0xFF, 0x00, il est tard si nous espérons que le prochain answerer va mettre des mots (il peut-être vous aide assez), mais voici un parseMarker autre et d'accompagnement handleParseResult:

parseMarker = do   -- or call it "parsePotentialMarker"
  part1 <- word8 0xFF
  part2 <- anyWord8
  return $
    if (part2 /= 0)
        then [(part1, part2)]
        else []

-- ... skipping other functions...
handleParseResult result = do
  case result of
    Fail _ _ msg -> msg
    Done _ r -> show (concat r)
-- ...

Sur une note côté, dans les questions qu'il aide un peu à un test entièrement fonctionnel dans le code, quelque chose comme:

main =
  let contents = BS.pack [1,2,3,4,0xFF,1 {- marker 1 -},0xFF,0x00,0xFF,2 {- marker 2 -},31,13,0xFF,0x00]
  in putStrLn $ parseJPEG contents
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top