質問

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 入力を消費しますが、途中で失敗する可能性があります。0xff0x00に遭遇したときに「巻き戻す」ことができ、別のパースを再試行する必要があります。

attoparsecはインストールされていませんが、デフォルトでバックトラックしないのはパルセックに似ていると思います。

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