attoparsecを使用したJPEGマーカーの解析
-
26-09-2019 - |
質問
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
解決
以来 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
所属していません StackOverflow