سؤال

كمشروع لزيادة معرفتي وراحة مع 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

هل كانت مفيدة؟

المحلول

حيث parseMarker تستهلك المدخلات ولكن قد تفشل في الجبال ، يجب أن تكون قادرًا على "الترجيح" وإعادة محيط تحليل مختلف عندما تواجه 0xFF 0x00.

ليس لديّ ATTOPARSEC مثبتًا ولكني أفترض أنه يشبه PARSEC الذي لا يتراجع بشكل افتراضي.

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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top