Pergunta

Como projeto para promover meu conhecimento e conforto com a Haskell, estou trabalhando para implementar um decodificador JPEG que será útil para o futuro trabalho de visão computacional.

O primeiro passo que escolhi é analisar todos os "marcadores" na imagem. Estes são indicados pelo byte 0XFF, seguidos por um byte não 0. Um byte 0xFF seguido de um byte 0x00 deve ser tratado como dados normais.

O problema que estou concordando é que, ao encontrar uma combinação 0xff 0x00, a análise parece terminar completamente e não são encontrados marcadores mais válidos (se você executar em um JPEG padrão, verá o início do marcador de imagem analisado, mas não o fim do Marcador de imagem como frequentemente 0xff 0x00 ocorre dentro dos próprios dados da imagem).

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

Foi útil?

Solução

Desde parseMarker Considera entrada, mas pode falhar no meio do caminho, você deve poder "retratar" e tentar uma análise diferente quando encontrar um 0xff 0x00.

Não tenho o AtToparsec instalado, mas presumo que seja semelhante ao Parsec, o que não é o retorno por padrão.

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

Outras dicas

O problema é que você não diz para analisar uma sequência de 0xff, 0x00, é tarde, então espero que o próximo respondente coloque palavras (talvez isso ajude você o suficiente), mas aqui está um alternativo parseMarker e acompanhando 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)
-- ...

Em uma nota lateral, em perguntas, ajuda um pouco a fazer um teste totalmente funcional no código, algo como:

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top