packages feed

image-type (empty) → 0.1.0.0

raw patch · 4 files changed

+378/−0 lines, 4 filesdep +basedep +bytestringsetup-changed

Dependencies added: base, bytestring

Files

+ Codec/ImageType.hs view
@@ -0,0 +1,273 @@+{-# LANGUAGE OverloadedStrings, MonadComprehensions #-}++{-|+Module      : Codec.ImageType+Description : A library for inferring image type by looking at a file's initial bytes+License     : BSD3+Maintainer  : Baldur Blöndal <baldurpet@gmail.com>++Infers an image's type by looking at its initial values and comparing against some magic bytes:++>>> :set -XOverloadedStrings+>>> import Codec.ImageType+>>> import System.IO+>>> import qualified Data.ByteString as B+>>> +>>> h <- openFile "/tmp/1_webp_ll.webp" ReadMode+>>> bytes <- hGet h 32+>>> B.isInfixOf "RIFF" bytes+True+>>> bytes+"RIFF\144h\SOH\NULWEBPVP8L\131h\SOH\NUL/\143\SOHK\DLE\141\&8l\219F\146\224"+>>> getFileType "/tmp/1_webp_ll.webp"+Just "webp"++Some other examples:++>>> import System.Process+>>> import System.Directory+>>> import Control.Monad+>>> let findTiffs = lines <$> readProcess "locate" ["*.tiff"] ""+>>> length <$> findTiffs+25+>>> findTiffs >>= filterM doesFileExist >>= mapM getFileType+[Just "tiff",Just "tiff", …+>>> sequence_ <$> (findTiffs >>= filterM doesFileExist >>= mapM getFileType)+Just ()+-}++module Codec.ImageType (+  -- * Actions+  getFileType,+  getFileTypes,++  -- * Predicates+  isJpeg,+  isPng,+  isGif,+  isTiff,+  isRgb,+  isPbm,+  isPgm,+  isPpm,+  isRast,+  isXbm,+  isBmp,+  isWebp,+  isExr,++  -- * Getting file type name+  testJpeg,+  testPng,+  testGif,+  testTiff,+  testRgb,+  testPbm,+  testPgm,+  testPpm,+  testRast,+  testXbm,+  testBmp,+  testWebp,+  testExr+  ) where++import Prelude hiding                   (length, head, take, drop)+import System.IO                        (withFile, IOMode(ReadMode))+import Data.ByteString                  (ByteString, length, hGet, head, take, drop, index, isPrefixOf)+import qualified Data.ByteString as BS+import Control.Monad                    (guard)+import Data.Maybe                       (isJust, catMaybes, listToMaybe)+import Control.Applicative              ((<$>))++-- | Performs an action on the first 32-bytes of a given file.+reading :: FilePath -> (ByteString -> r) -> IO r+reading file test = withFile file ReadMode $ \h -> do+  bytes <- hGet h 32+  return (length bytes `seq` test bytes)++-- | Joint Photographic Experts Group (JPEG). Returns @Just "jpeg"@ if+-- file satisfies check.+testJpeg :: ByteString -> Maybe String+testJpeg bytes = [ "jpeg"+                 | take 4 (drop 6 bytes) `elem` ["JFIF", "Exif"]+                 ]++-- | Checks if file is @jpeg@.+-- +-- >>> import Codec.ImageType +-- >>> import Control.Monad+-- >>> import System.Directory+-- >>> +-- >>> +-- >>> getDirectoryContents "." >>= filterM doesFileExist >>= filterM isJpeg+-- ["file2.jpeg","file1.jpeg"]+-- +isJpeg :: FilePath -> IO Bool+isJpeg file = isJust <$> reading file testJpeg++-- | Portable Network Graphics (PNG). Returns @Just "png"@ if file+-- satisfies check against magic number @89 50 4e 47 0d 0a 1a 0a@.+testPng :: ByteString -> Maybe String+testPng bytes = [ "png"+                | isPrefixOf "\137PNG\r\n\26\n" bytes+                ]++-- | Checks if file is @png@.+isPng :: FilePath -> IO Bool+isPng file = isJust <$> reading file testPng++-- | Graphics Interchange Format (GIF). Returns @Just "gif"@ if file+-- satisfies check against magic number @GIF87a@ and @GIF89a@.+testGif :: ByteString -> Maybe String+testGif bytes = [ "gif"+                | elem (take 6 bytes) ["GIF87a", "GIF89a"]+                ]++-- | Checks if file is @gif@.+isGif :: FilePath -> IO Bool+isGif file = isJust <$> reading file testGif++-- | Tagged Image File Format (TIFF). Returns @Just "tiff"@ if first+-- short is @II@ or @MM@.+testTiff :: ByteString -> Maybe String+testTiff bytes = [ "tiff"+                 | elem (take 2 bytes) ["MM", "II"]+                 ]++-- | Checks if file is @tiff@.+isTiff :: FilePath -> IO Bool+isTiff file = isJust <$> reading file testTiff++-- | SGI image library. Checks magic number (decimal value 474 as a+-- short) that identifies file as an SGI image file and then returns+-- @Just "rgb"@.+testRgb :: ByteString -> Maybe String+testRgb bytes = [ "rgb"+                | isPrefixOf "\001\218" bytes+                ]++-- | Checks if file is @rgb@.+isRgb :: FilePath -> IO Bool+isRgb file = isJust <$> reading file testRgb++-- | PBM (portable bitmap). Returns @Just "pbm"@ if file satisfies check.+testPbm :: ByteString -> Maybe String+testPbm bytes = [ "pbm"+                | length bytes >= 3+                , index bytes(0) == head "P"+                , index bytes(1) `BS.elem` "14"+                , index bytes(2) `BS.elem` " \t\n\r"+                ]++-- | Checks if file is @pbm@. +isPbm :: FilePath -> IO Bool+isPbm file = isJust <$> reading file testPbm++-- | PGM (portable graymap). Returns @Just "pgm"@ if file satisfies check.+testPgm :: ByteString -> Maybe String+testPgm bytes = [ "pgm"+                | length bytes >= 3+                , index bytes(0) == head "P"+                , index bytes(1) `BS.elem` "25"+                , index bytes(2) `BS.elem` " \t\n\r"+                ]++-- | Checks if file is @pgm@.+isPgm :: FilePath -> IO Bool+isPgm file = isJust <$> reading file testPgm++-- | PPM (portable pixmap). Returns @Just "ppm"@ if file satisfies check.+testPpm :: ByteString -> Maybe String+testPpm bytes = [ "ppm"+                | length bytes >= 3+                , index bytes(0) == head "P"+                , index bytes(1) `BS.elem` "36"+                , index bytes(2) `BS.elem` " \t\n\r"+                ]++-- | Checks if file is @ppm@.+isPpm :: FilePath -> IO Bool+isPpm file = isJust <$> reading file testPpm++-- | Sun raster file. Returns @Just "rast"@ if file satisfies check.+testRast :: ByteString -> Maybe String+testRast bytes = [ "rast"+                 | isPrefixOf "\x59\xA6\x6A\x95" bytes+                 ]++-- | Checks if file is @rast@.+isRast :: FilePath -> IO Bool+isRast file = isJust <$> reading file testRast++-- | X bitmap (X10 or X11). Returns @Just "xbm"@ if file satisfies check.+testXbm :: ByteString -> Maybe String+testXbm bytes = [ "xbm"+                | isPrefixOf "#define " bytes+                ]++-- | Checks if file is @xbm@.+isXbm :: FilePath -> IO Bool+isXbm file = isJust <$> reading file testXbm++-- | Bitmap (BMP) file format. Returns @Just "bmp"@ if file satisfies check.+testBmp :: ByteString -> Maybe String+testBmp bytes = [ "bmp"+                | isPrefixOf "BM" bytes+                ]++-- | Checks if file is @bmp@.+isBmp :: FilePath -> IO Bool+isBmp file = isJust <$> reading file testBmp++-- | WebP. Returns @Just "webp"@ if file satisfies check.+testWebp :: ByteString -> Maybe String+testWebp bytes = [ "webp"+                 | isPrefixOf "RIFF" bytes+                 , take 4 (drop 8 bytes) == "WEBP"+                 ]++-- | Checks if file is @webp@.+isWebp :: FilePath -> IO Bool+isWebp file = isJust <$> reading file testWebp++-- | OpenEXR. Returns @Just "exr"@ if file satisfies check.+testExr :: ByteString -> Maybe String+testExr bytes = [ "exr"+                | isPrefixOf "\x76\x2f\x31\x01" bytes+                ]++-- | Checks if file is @exr@.+isExr :: FilePath -> IO Bool+isExr file = isJust <$> reading file testExr++tests :: [ByteString -> Maybe String]+tests = [testJpeg, testPng, testGif,+         testTiff, testRgb, testPbm,+         testPgm, testPpm, testRast,+         testXbm, testBmp, testWebp,+         testExr]++-- | Gets a ginel possible file types based on fairly arbitrary tie+-- breaking.+-- +-- >>> import System.Directory+-- >>> import Control.Monad+-- >>> getDirectoryContents "." >>= filterM doesFileExist >>= mapM getFileType+-- [Just "rast",Just "jpeg",Nothing,Just "webp",Just "gif",Just "pgm",Just "webp",Nothing,Just "webp",Just "exr"]+-- +getFileType :: FilePath -> IO (Maybe String)+getFileType file = reading file $ \bytes -> do+  listToMaybe $ catMaybes [ test bytes | test <- tests ]++-- | Gets possible file types. Returns empty list if nothing is found,+-- otherwise a list of matches.+-- +-- >>> import System.Directory+-- >>> import Control.Monad+-- >>> getDirectoryContents "." >>= filterM doesFileExist >>= mapM getFileTypes+-- [["rast"],["jpeg"],[],["webp"],["gif"],["pgm"],["webp"],[],["webp"],["exr"]]+-- +getFileTypes :: FilePath -> IO [String]+getFileTypes file = reading file $ \bytes -> do+  catMaybes [ test bytes | test <- tests ]
+ LICENSE view
@@ -0,0 +1,51 @@+Copyright (c) 2014, Baldur Blöndal++=======+Copyright (c) 2014, Icelandjack++    * 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 Baldur Blöndal 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.+=======+* 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 the {organization} nor the names of its+  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 HOLDER 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.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ image-type.cabal view
@@ -0,0 +1,52 @@+-- Initial image-type.cabal generated by cabal init.  For further +-- documentation, see http://haskell.org/cabal/users-guide/++name:                image-type+version:             0.1.0.0+synopsis:            Determine the type of an image by reading the first bytes. +description:         A package used to determine the type of an image according to its first bytes based on the Python library <https://docs.python.org/3/library/imghdr.html imghdr>.+  .+  Most simplest usage is getting the type of a file:+  .+  >>> import Codec.ImageType +  >>> getFileType "/tmp/mystery_file" +  Just "webp"+  .+  Or to test for a specific extension:+  .+  >>> isPgm "/tmp/file.pgm"+  True+  >>> import qualified Data.ByteString as B+  >>> testPgm <$> B.readFile "/tmp/file.pgm"+  Just "pgm"+  .+  Or to filter files by extension:+  .+  >>> import Codec.ImageType +  >>> import Control.Monad+  >>> import System.Directory+  >>> +  >>> getDirectoryContents "." >>= filterM doesFileExist >>= filterM isJpeg+  ["file2.jpeg","file1.jpeg"]+  .+  Supports the following extensions: @JPEG@, @PNG@, @GIF@, @TIFF@, @RGB@, @PBM@, @PGM@, @PPM@, @RAST@, @XBM@, @BMP@, @WebP@, @EXR@.+  .+homepage:            https://github.com/Icelandjack/Image-type+license:             BSD3+license-file:        LICENSE+author:              Baldur Blöndal+maintainer:          baldurpet@gmail.com+-- copyright:           +category:            Graphics+build-type:          Simple+-- extra-source-files:  +cabal-version:       >=1.10++library+  exposed-modules:     Codec.ImageType+  -- other-modules:       +  -- other-extensions:    +  build-depends:       base == 4.*,+                       bytestring >=0.9 && <0.11+  -- hs-source-dirs:      +  default-language:    Haskell98