Вопрос

В качестве проекта к дальнейшему мнению знаний и комфорта с 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.

Это было полезно?

Решение

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

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

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

Другие советы

Проблема в том, что вы не говорите об этом разбирать последовательность 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top