作为一个通过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
答案 0 :(得分:2)
由于parseMarker
消耗输入但可能在中途失败,因此当您遇到0xFF 0x00时,您必须能够“倒回”并重试另一个解析。
我没有安装Attoparsec,但我认为它与Parsec类似,默认情况下不会回溯。
parseSection =
skipMany (notWord8 0xFF <|> try (word8 0xFF >> word8 0x0)) >> parseMarker
答案 1 :(得分:1)
问题是你不要告诉它解析一个0xFF,0x00的序列,它已经晚了所以希望下一个回答者会给它添加文字(它可能对你有所帮助),但这里有一个替代{{1 }和随附的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)
-- ...