JPEG -Marker mit Attoparsec analysieren
-
26-09-2019 - |
Frage
Als Projekt, um mein Wissen und mein Komfort mit Haskell zu fördern, arbeite ich an der Implementierung eines JPEG -Decoders, der für zukünftige Computer -Vision -Arbeiten nützlich sein wird.
Der erste Schritt, den ich ausgewählt habe, besteht darin, alle "Marker" innerhalb des Bildes zu analysieren. Diese werden durch das Byte 0xff angezeigt, gefolgt von einem Nicht-0-Byte. Ein 0xff -Byte, gefolgt von einem 0x00 -Byte, muss als normale Daten behandelt werden.
Das Problem, in das ich mich begegnung habe Bildmarkierung wie häufig 0xff 0x00 tritt innerhalb der Bilddaten selbst auf).
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
Lösung
Seit parseMarker
Eingänge konsumiert, aber es kann möglicherweise gleichbleibend nicht bestehen. Sie müssen in der Lage sein, "zurückzuspulen" und einen anderen Analyse wiederholen zu können, wenn Sie auf einen 0xff 0x00 stoßen.
Ich habe keine Attoparsec installiert, aber ich gehe davon aus, dass es Parsec ähnelt, was standardmäßig nicht zurückverfolgt.
parseSection =
skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker
Andere Tipps
Das Problem ist, dass Sie es nicht sagen, eine Sequenz von 0xff, 0x00 zu analysieren, es ist spät. Hoffentlich wird der nächste Answereter Worte geben (es hilft Ihnen vielleicht genug), aber hier ist eine Alternative parseMarker
und begleitet 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)
-- ...
Nebenbei bemerkt, in Fragen hilft es leicht, einen voll funktionsfähigen Test im Code zu haben, so etwas wie:
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