imagesize-conduit (empty) → 0.2.0
raw patch · 8 files changed
+186/−0 lines, 8 filesdep +HUnitdep +basedep +bytestringsetup-changedbinary-added
Dependencies added: HUnit, base, bytestring, conduit, hspec, imagesize-conduit
Files
- Data/Conduit/ImageSize.hs +89/−0
- LICENSE +30/−0
- Setup.lhs +7/−0
- imagesize-conduit.cabal +39/−0
- test/logo.gif binary
- test/logo.jpg binary
- test/logo.png binary
- test/main.hs +21/−0
+ Data/Conduit/ImageSize.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE OverloadedStrings #-}+module Data.Conduit.ImageSize+ ( sinkImageSize+ , Size (..)+ ) where++import qualified Data.ByteString.Lazy as L+import qualified Data.Conduit as C+import qualified Data.Conduit.Binary as CB+import qualified Data.ByteString as S+import Data.ByteString.Char8 ()+import Data.ByteString.Lazy.Char8 ()+import Control.Applicative ((<$>), (<*>))++data Size = Size { width :: Int, height :: Int }+ deriving (Show, Eq, Ord, Read)++sinkImageSize :: C.Resource m => C.Sink S.ByteString m (Maybe Size)+sinkImageSize =+ C.SinkData (pushHeader id) close+ where+ close = return Nothing+ pushHeader front bs'+ | S.length bs >= 11 && S.take 5 (S.drop 6 bs) ==+ S.pack [0x4A, 0x46, 0x49, 0x46, 0x00] =+ C.sinkPush jpg $ S.drop 4 bs+ | S.length bs >= 6 && S.take 6 bs `elem` gifs =+ C.sinkPush gif $ S.drop 6 bs+ | S.length bs >= 8 && S.take 8 bs == S.pack [137, 80, 78, 71, 13, 10, 26, 10] =+ C.sinkPush png $ S.drop 8 bs+ | S.length bs < 11 = do+ return $ C.Processing (pushHeader $ S.append bs) close+ | otherwise = do+ return $ C.Done (Just bs) Nothing+ where+ 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)+ _ -> 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 $ Size <$> 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++ jpgFrame = do+ mx <- CB.head+ case mx of+ Just 255 -> do+ my <- CB.head+ case my of+ Just 0xC0 -> do+ _ <- CB.take 3+ h <- getInt 2 0+ w <- getInt 2 0+ return $ Size <$> w <*> h+ Just _ -> jpg+ Nothing -> return Nothing+ _ -> return Nothing++getInt :: (C.Resource m, Integral i)+ => Int+ -> i+ -> C.Sink 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)
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Michael Snoyman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Michael Snoyman nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,7 @@+#!/usr/bin/env runhaskell++> module Main where+> import Distribution.Simple++> main :: IO ()+> main = defaultMain
+ imagesize-conduit.cabal view
@@ -0,0 +1,39 @@+Name: imagesize-conduit+Version: 0.2.0+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+Category: Graphics, Conduit+Build-type: Simple+Cabal-version: >=1.8+Homepage: http://github.com/snoyberg/conduit+extra-source-files: test/main.hs+ test/logo.png+ test/logo.gif+ test/logo.jpg++Library+ Exposed-modules: Data.Conduit.ImageSize+ Build-depends: base >= 4 && < 5+ , conduit >= 0.2 && < 0.3+ , bytestring >= 0.9+ ghc-options: -Wall++test-suite test+ hs-source-dirs: test+ main-is: main.hs+ type: exitcode-stdio-1.0+ build-depends: conduit+ , imagesize-conduit+ , base+ , hspec+ , HUnit+ , bytestring+ ghc-options: -Wall++source-repository head+ type: git+ location: git://github.com/snoyberg/conduit.git
+ test/logo.gif view
binary file changed (absent → 3633 bytes)
+ test/logo.jpg view
binary file changed (absent → 10825 bytes)
+ test/logo.png view
binary file changed (absent → 10661 bytes)
+ test/main.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE OverloadedStrings #-}+import qualified Data.Conduit as C+import qualified Data.Conduit.Binary as CB+import Data.Conduit.ImageSize++import Test.Hspec.Monadic+import Test.Hspec.HUnit ()+import Test.HUnit++main :: IO ()+main = hspecX $ 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 "invalid" $ check Nothing "test/main.hs"++check :: Maybe Size -> FilePath -> Assertion+check ex fp = do+ size <- C.runResourceT $ CB.sourceFile fp C.$$ sinkImageSize+ size @?= ex