Parsing 如何有效地解析熵编码的JPEG块?

Parsing 如何有效地解析熵编码的JPEG块?,parsing,haskell,jpeg,attoparsec,Parsing,Haskell,Jpeg,Attoparsec,我只是想跳过一个.JPEG文件中的SOS_MT块,我不想用这些数据做任何事情,我只想知道它的结尾。据我所知,虽然JPEG文件中的所有其他块都以表示块长度的几个字节开头,但SOS_MT块是。。。好吧,这是一个邪恶的沼泽,你别无选择,只能逐个字节地解析,直到它结束 因此,我提供了以下代码来实现这一点: entropyCoded :: Parser Int entropyCoded = do list_of_lengths <- many' $ (

我只是想跳过一个.JPEG文件中的SOS_MT块,我不想用这些数据做任何事情,我只想知道它的结尾。据我所知,虽然JPEG文件中的所有其他块都以表示块长度的几个字节开头,但SOS_MT块是。。。好吧,这是一个邪恶的沼泽,你别无选择,只能逐个字节地解析,直到它结束

因此,我提供了以下代码来实现这一点:

entropyCoded :: Parser Int
entropyCoded = do
    list_of_lengths <-  many' $
         (
           do
             _ <- notWord8 0xFF
             return 1
         )
         <|>
         (
           do
             _ <- word8 0xFF
             _ <- word8 0
             return 2
         )
         <|>
         (
           do
             l <- many1 (word8 0xFF)
             _ <- satisfy (\x -> ( x >= 0xD0 && x < 0xD7 ))
             return $ 1 + length l
         )
         <|>
         (
           do
             _ <- word8 0xFF
             maybe_ff <- peekWord8'
             if maybe_ff == 0xFF
               then
                 return 1
               else
                 fail "notthere"
         )
    foldM (\ nn n -> nn `seq` return (nn + n) ) 0 list_of_lengths
entropyCoded::Parser Int
entropyCoded=do
长度列表nn`seq`return(nn+n))0长度列表

这段代码使用的是,据我有机会验证它,它是正确的。就是慢。关于如何改进此解析器性能的任何提示?

如果您想跳过SOS市场,只需寻找下一个不是重启标记的标记


读取字节,直到找到和。如果下一个值为00,则它是一个压缩的FF值,并跳过它。如果是重新启动标记,跳过它。否则,FF应开始下一个区块。

如果您想跳过SOS市场,只需查找下一个不是重启标记的标记即可


读取字节,直到找到和。如果下一个值为00,则它是一个压缩的FF值,并跳过它。如果是重新启动标记,跳过它。否则,FF应开始下一个程序段。

根据标准,在上一个答案的基础上增加一个小部分:

B.1.1.5熵编码数据段

熵编码数据段包含熵编码过程的输出。它由整数个字节组成,无论使用的熵编码过程是哈夫曼编码还是算术编码

附注1

将熵编码段设置为整数字节数,如下所示:对于哈夫曼编码,如有必要,使用1位填充压缩数据的结尾,以完成段的最后一个字节。对于算术编码,字节对齐 在终止熵编码段的程序中执行(见D.1.8)

附注2

为了确保标记不会出现在熵编码段内,遵循由Huffman或算术编码器生成的任何X'FF'字节,或由上文注释1中所述的1位填充生成的X'FF'字节 通过“填充”零字节(见D.1.6和F.1.2.3)


因此,当您在位置N处的熵编码部分中输入0xFF时,再向前读取一个字节。如果下一个字节是0x00,则它是“填充”零。如果是另一个0xFF,则存在填充,请从N+1重新检查。每隔一个字节(0x01-0xFE)就是下一个标记的一部分。

根据标准,是对上一个答案的一个小补充:

B.1.1.5熵编码数据段

熵编码数据段包含熵编码过程的输出。它由整数个字节组成,无论使用的熵编码过程是哈夫曼编码还是算术编码

附注1

将熵编码段设置为整数字节数,如下所示:对于哈夫曼编码,如有必要,使用1位填充压缩数据的结尾,以完成段的最后一个字节。对于算术编码,字节对齐 在终止熵编码段的程序中执行(见D.1.8)

附注2

为了确保标记不会出现在熵编码段内,遵循由Huffman或算术编码器生成的任何X'FF'字节,或由上文注释1中所述的1位填充生成的X'FF'字节 通过“填充”零字节(见D.1.6和F.1.2.3)


因此,当您在位置N处的熵编码部分中输入0xFF时,再向前读取一个字节。如果下一个字节是0x00,则它是“填充”零。如果是另一个0xFF,则存在填充,请从N+1重新检查。每隔一个字节(0x01-0xFE)就是下一个标记的一部分。

压缩图像数据夹在FFDA和FFD9之间。问题是FFD9可能丢失,文件应该在那里结束。我不理解你“跳过”SOS_MT块的目的。没有“通过”也没有“在另一边”。首先,(可能)通过使用为二进制序列化设计的库(我偏爱)。其次,每个分支无条件地解析一个单词。与其解析该单词,并在以后失败时进行回溯,不如解析该单词,并根据其值决定下一步要做什么。最后(对此不确定)与其计算和求和长度,不如使用来获得解析后的字符串,他们只需计算其长度。@BitBank如果我没有正确理解,请原谅我,但是progressive.JPEG的多个过程如何?不是每个过程都使用不同的SOS_MT块吗?谢谢@user2407038,你关于分解单词解析的建议很好。对于p在前进图像中,在每次扫描的开始处都有一个SOS(FFDA)。这个字节序列(FFDA)只能解释为SOS标记;具有FFDA序列的压缩数据将被编码为FF00DA。压缩图像数据夹在FFDA和FFD9之间。问题是FFD9可能丢失,文件应该到此结束。我不理解您“跳过”SOS_MT块的目的。首先,(可能)通过使用一个为二进制序列化而设计的库(我偏爱)。其次,每个分支无条件地解析一个单词。不要解析那个词,如果以后失败了,就回溯,而应该解析那个词,并根据它的值决定下一步要做什么。最后(不确定这一点)不是计算长度并求和,而是使用来获取解析的字符串,它们只是计算其长度。@BitBank如果我没有正确理解,请原谅,但是progressive.JPEG的多次传递呢?做