Domanda

Come progetto per promuovere la mia conoscenza e conforto con Haskell, sto lavorando per implementare un decodificatore JPEG che tornerà utile per il futuro lavoro di visione artificiale.

Il primo passo che ho scelto è quello di analizzare tutti i "marcatori" all'interno dell'immagine. Questi sono indicati dal byte 0xFF seguito da un byte non 0. Un byte 0xFF seguito da un byte 0x00 deve essere trattato come dati normali.

Il problema in cui mi sto imbattendo è che dopo aver incontrato una combinazione 0xFF 0x00, l'analisi sembra finire completamente e non si trovano più marcatori validi (se si esegue su un JPEG standard, vedrai l'inizio del marcatore di immagini analizzato, ma non la fine di Marker di immagine come spesso 0xFF 0x00 si verifica all'interno dei dati dell'immagine stessa).

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

È stato utile?

Soluzione

Da parseMarker consuma input ma potrebbe fallire a metà strada, devi essere in grado di "riavvolgere" e riprovare uno slancio diverso quando si incontra un 0xFF 0x00.

Non ho installato ATTOPASSEC, ma presumo che sia simile a Parsec che non è tornato indietro per impostazione predefinita.

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

Altri suggerimenti

Il problema è che non lo dici di analizzare una sequenza di 0xFF, 0x00, è tardi, quindi spero che il prossimo risposta metta le parole (forse ti aiuta abbastanza), ma ecco un alternativo parseMarker e accompagnare 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)
-- ...

In una nota a margine, nelle domande aiuta leggermente ad avere un test completamente funzionale nel codice, qualcosa come:

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top