imagesize-conduit 1.0.0.2 → 1.0.0.3
raw patch · 3 files changed
+83/−71 lines, 3 filesdep +conduit-extradep +resourcetdep ~bytestringdep ~conduitdep ~hspecnew-uploader
Dependencies added: conduit-extra, resourcet
Dependency ranges changed: bytestring, conduit, hspec
Files
- Data/Conduit/ImageSize.hs +66/−58
- imagesize-conduit.cabal +11/−8
- test/main.hs +6/−5
Data/Conduit/ImageSize.hs view
@@ -1,11 +1,13 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE DeriveDataTypeable #-}+-- | Detect the image size without opening the image itself. module Data.Conduit.ImageSize- ( sinkImageSize- , Size (..)- , sinkImageInfo- , FileFormat (..)- ) where+ ( Size (..)+ , FileFormat (..)+ , sinkImageInfo+ , sinkImageSize+ ) where import qualified Data.ByteString.Lazy as L import Data.Conduit@@ -13,90 +15,96 @@ import qualified Data.ByteString as S import Data.ByteString.Char8 () import Data.ByteString.Lazy.Char8 ()+import qualified Data.Typeable as T import Control.Applicative ((<$>), (<*>)) + data Size = Size { width :: Int, height :: Int }- deriving (Show, Eq, Ord, Read)+ deriving (Show, Eq, Ord, Read, T.Typeable) + data FileFormat = GIF | PNG | JPG- deriving (Show, Eq, Ord, Read, Enum)+ deriving (Show, Eq, Ord, Read, Enum, T.Typeable) + -- | Specialized version of 'sinkImageInfo' that returns only the -- image size. sinkImageSize :: Monad m => Consumer S.ByteString m (Maybe Size) sinkImageSize = fmap (fmap fst) sinkImageInfo + -- | Find out the size of an image. Also returns the file format -- that parsed correctly. Note that this function does not -- verify that the file is indeed in the format that it returns, -- since it looks only at a small part of the header. sinkImageInfo :: Monad m => Consumer S.ByteString m (Maybe (Size, FileFormat))-sinkImageInfo =- start id+sinkImageInfo = start id where start front = await >>= maybe (return Nothing) (pushHeader front) pushHeader front bs'- | S.length bs >= 11 && S.take 5 (S.drop 6 bs) ==- S.pack [0x4A, 0x46, 0x49, 0x46, 0x00] =- leftover (S.drop 4 bs) >> jpg- | S.length bs >= 6 && S.take 6 bs `elem` gifs =- leftover (S.drop 6 bs) >> gif- | S.length bs >= 8 && S.take 8 bs == S.pack [137, 80, 78, 71, 13, 10, 26, 10] =- leftover (S.drop 8 bs) >> png- | S.length bs < 11 = start $ S.append bs- | otherwise = leftover bs >> return Nothing+ | S.length bs >= 11 && S.take 3 bs == S.pack [0xFF, 0xD8, 0xFF] =+ leftover (S.drop 4 bs) >> jpg+ | S.length bs >= 6 && S.take 6 bs `elem` gifs =+ leftover (S.drop 6 bs) >> gif+ | S.length bs >= 8 && S.take 8 bs == S.pack [137, 80, 78, 71, 13, 10, 26, 10] =+ leftover (S.drop 8 bs) >> png+ | S.length bs < 11 = start $ S.append bs+ | otherwise = leftover bs >> return Nothing where- bs = front bs'+ bs = front bs' gifs = ["GIF87a", "GIF89a"] gif = do- b <- CB.take 4- let go x y = fromIntegral x + (fromIntegral y) * 256- return $ case L.unpack b of- [w1, w2, h1, h2] -> Just (Size (go w1 w2) (go h1 h2), GIF)- _ -> Nothing+ b <- CB.take 4+ let go x y = fromIntegral x + (fromIntegral y) * 256+ return $ case L.unpack b of+ [w1, w2, h1, h2] -> Just (Size (go w1 w2) (go h1 h2), GIF)+ _ -> Nothing png = do- _ <- CB.take 4 -- FIXME drop- hdr <- CB.take 4- if hdr == "IHDR"- then do- mw <- getInt 4 0- mh <- getInt 4 0- return $ (\w h -> (Size w h, PNG)) <$> mw <*> mh- else return Nothing+ CB.drop 4+ hdr <- CB.take 4+ if hdr == "IHDR"+ then do+ mw <- getInt 4 0+ mh <- getInt 4 0+ return $ (\w h -> (Size w h, PNG)) <$> mw <*> mh+ else return Nothing jpg = do- mi <- getInt 2 0- case mi of- Nothing -> return Nothing- Just i -> do- _ <- CB.take $ i - 2- jpgFrame+ mi <- getInt 2 0+ case mi of+ Nothing -> return (Just (Size 1 1, JPG))+ Just i -> do+ CB.drop $ i - 2+ jpgFrame + jpgSofMarkerBytes = [0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7,+ 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF]+ jpgFrame = do- mx <- CB.head- case mx of- Just 255 -> do- my <- CB.head- case my of- Just 0xC0 -> do- _ <- CB.take 3- mh <- getInt 2 0- mw <- getInt 2 0- return $ (\w h -> (Size w h, JPG)) <$> mw <*> mh- Just _ -> jpg- Nothing -> return Nothing- _ -> return Nothing+ mx <- CB.head+ case mx of+ Just 0xFF -> do+ my <- CB.head+ case my of+ Just b | b `elem` jpgSofMarkerBytes -> do+ _ <- CB.take 3+ mh <- getInt 2 0+ mw <- getInt 2 0+ return $ (\w h -> (Size w h, JPG)) <$> mw <*> mh+ Just _ -> jpg+ Nothing -> return Nothing+ _ -> return Nothing getInt :: (Monad m, Integral i)- => Int- -> i- -> Consumer S.ByteString m (Maybe i)+ => Int+ -> i+ -> Consumer S.ByteString m (Maybe i) getInt 0 i = return $ Just i getInt len i = do- mx <- CB.head- case mx of- Nothing -> return Nothing- Just x -> getInt (len - 1) (i * 256 + fromIntegral x)+ mx <- CB.head+ case mx of+ Nothing -> return Nothing+ Just x -> getInt (len - 1) (i * 256 + fromIntegral x)
imagesize-conduit.cabal view
@@ -1,15 +1,15 @@ Name: imagesize-conduit-Version: 1.0.0.2-Synopsis: Determine the size of some common image formats. (deprecated)+Version: 1.0.0.3+Synopsis: Determine the size of some common image formats. Description: Currently supports PNG, GIF, and JPEG. This package provides a Sink that will consume the minimum number of bytes necessary to determine the image dimensions. License: BSD3 License-file: LICENSE Author: Michael Snoyman-Maintainer: michael@snoyman.com+Maintainer: Mikael Brockman <mikael@silk.co>, Felipe Lessa <felipe.lessa@gmail.com> Category: Graphics, Conduit Build-type: Simple Cabal-version: >=1.8-Homepage: http://github.com/snoyberg/conduit+Homepage: http://github.com/silkapp/imagesize-conduit extra-source-files: test/main.hs test/logo.png test/logo.gif@@ -18,8 +18,9 @@ Library Exposed-modules: Data.Conduit.ImageSize Build-depends: base >= 4 && < 5- , conduit >= 1.0 && < 1.1- , bytestring >= 0.9+ , conduit >= 1.1 && < 1.2+ , conduit-extra >= 1.1 && < 1.2+ , bytestring >= 0.10 ghc-options: -Wall test-suite test@@ -27,12 +28,14 @@ main-is: main.hs type: exitcode-stdio-1.0 build-depends: conduit+ , conduit-extra+ , resourcet , imagesize-conduit , base- , hspec >= 1.3+ , hspec >= 1.10 , bytestring ghc-options: -Wall source-repository head type: git- location: git://github.com/snoyberg/conduit.git+ location: git://github.com/silkapp/imagesize-conduit.git
test/main.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} import qualified Data.Conduit as C import qualified Data.Conduit.Binary as CB+import Control.Monad.Trans.Resource (runResourceT) import Data.Conduit.ImageSize import Test.Hspec@@ -8,12 +9,12 @@ main :: IO () main = hspec $ do describe "image size" $ do- it "png" $ check (Just $ Size 271 61) "test/logo.png"- it "jpg" $ check (Just $ Size 271 61) "test/logo.jpg"- it "gif" $ check (Just $ Size 271 61) "test/logo.gif"+ it "png" $ check (Just (Size 271 61, PNG)) "test/logo.png"+ it "jpg" $ check (Just (Size 271 61, JPG)) "test/logo.jpg"+ it "gif" $ check (Just (Size 271 61, GIF)) "test/logo.gif" it "invalid" $ check Nothing "test/main.hs" -check :: Maybe Size -> FilePath -> Expectation+check :: Maybe (Size, FileFormat) -> FilePath -> Expectation check ex fp = do- size <- C.runResourceT $ CB.sourceFile fp C.$$ sinkImageSize+ size <- runResourceT $ CB.sourceFile fp C.$$ sinkImageInfo size `shouldBe` ex