Анализ маркеров JPEG с помощью attoparsec - PullRequest
2 голосов
/ 06 января 2011

Как проект, расширяющий мои знания и комфорт с Haskell, я работаю над внедрением декодера JPEG, который пригодится для будущей работы с компьютерным зрением.

Первый шаг, который я выбрал, - это разбор всех "Маркеры »внутри изображения.Они обозначены байтом 0xFF, за которым следует байт, отличный от 0.Байт 0xFF, за которым следует байт 0x00, следует рассматривать как нормальные данные.

Проблема, с которой я сталкиваюсь, заключается в том, что при обнаружении комбинации 0xFF 0x00 синтаксический анализ, по-видимому, завершается полностью, и больше не обнаруживаются действительные маркеры (еслипри запуске стандартного JPEG вы увидите начало разбора маркера изображения, но не конец маркера изображения, так как часто 0xFF 0x00 встречается в самих данных изображения).

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

Ответы [ 2 ]

2 голосов
/ 06 января 2011

Поскольку parseMarker потребляет входные данные, но может частично потерпеть неудачу, вы должны иметь возможность "перемотать" и повторить другой анализ, когда вы обнаружите 0xFF 0x00.

У меня не установлен Attoparsec, ноЯ предполагаю, что это похоже на Parsec, который не возвращается по умолчанию.

parseSection =
    skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker
1 голос
/ 06 января 2011

Проблема в том, что вы не говорите ему анализировать последовательность 0xFF, 0x00, уже поздно, поэтому мы надеемся, что следующий ответчик добавит слова (возможно, это вам достаточно поможет), но здесь есть альтернатива parseMarker и сопровождающие 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)
-- ...

С другой стороны, в вопросах немного помогает иметь полностью функциональный тест в коде, что-то вроде:

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
...