3

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

4

2 に答える 2

2

parseMarker入力を消費しますが、途中で失敗する可能性があるため、0xFF 0x00に遭遇した場合は、「巻き戻し」して別の解析を再試行できる必要があります。

Attoparsecをインストールしていませんが、デフォルトでバックトラックしないParsecに似ていると思います。

parseSection =
    skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker
于 2011-01-06T05:00:00.783 に答える
1

問題は、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
于 2011-01-06T05:08:31.293 に答える