repa-io (empty) → 1.1.0.0
raw patch · 8 files changed
+483/−0 lines, 8 filesdep +basedep +bmpdep +dph-prim-parsetup-changed
Dependencies added: base, bmp, dph-prim-par, repa, repa-bytestring
Files
- Data/Array/Repa/IO/BMP.hs +186/−0
- Data/Array/Repa/IO/ColorRamp.hs +48/−0
- Data/Array/Repa/IO/Internals/Text.hs +41/−0
- Data/Array/Repa/IO/Matrix.hs +67/−0
- Data/Array/Repa/IO/Vector.hs +75/−0
- LICENSE +24/−0
- Setup.hs +2/−0
- repa-io.cabal +40/−0
+ Data/Array/Repa/IO/BMP.hs view
@@ -0,0 +1,186 @@+{-# LANGUAGE PackageImports #-} ++-- | Reading and writing arrays as uncompressed 24 and 32 bit Windows BMP files.+module Data.Array.Repa.IO.BMP+ ( readImageFromBMP+ , readComponentsFromBMP+ , readMatrixFromGreyscaleBMP+ , writeImageToBMP+ , writeComponentsToBMP+ , writeMatrixToGreyscaleBMP)+where+import qualified Data.Array.Parallel.Unlifted as U+import Data.Array.Repa as A+import Data.Array.Repa.ByteString as A+import Prelude as P+import Codec.BMP+import Data.Word++-- Read -------------------------------------------------------------------------------------------+-- | Read a matrix from a `BMP` file.+-- Each pixel is converted to greyscale, normalised to [0..1] and used+-- as the corresponding array element. If anything goes wrong when loading the file then `Error`.+readMatrixFromGreyscaleBMP+ :: FilePath+ -> IO (Either Error (Array DIM2 Double))++readMatrixFromGreyscaleBMP filePath+ = do eComps <- readComponentsFromBMP filePath+ case eComps of + Left err -> return $ Left err+ Right (arrRed, arrGreen, arrBlue)+ -> let arr = force + $ A.fromFunction (extent arrRed)+ (\ix -> sqrt ( (fromIntegral (arrRed !: ix) / 255) ^ (2 :: Int)+ + (fromIntegral (arrGreen !: ix) / 255) ^ (2 :: Int)+ + (fromIntegral (arrBlue !: ix) / 255) ^ (2 :: Int)))+ in arr `deepSeqArray` return (Right arr)+ ++-- | Read RGB components from a BMP file.+-- Returns arrays of red, green and blue components, all with the same extent.+-- If anything goes wrong when loading the file then then `Error`.+readComponentsFromBMP+ :: FilePath+ -> IO (Either Error (Array DIM2 Word8, Array DIM2 Word8, Array DIM2 Word8))++{-# INLINE readComponentsFromBMP #-}+readComponentsFromBMP filePath+ = do ebmp <- readBMP filePath+ case ebmp of+ Left err -> return $ Left err+ Right bmp -> return $ Right (readComponentsFromBMP' bmp)++readComponentsFromBMP' bmp+ = let (width, height) = bmpDimensions bmp++ arr = A.fromByteString (Z :. height :. width * 4)+ $ unpackBMPToRGBA32 bmp++ shapeFn _ = Z :. height :. width++ arrRed + = traverse arr shapeFn+ (\get (sh :. x) -> get (sh :. (x * 4)))++ arrGreen+ = traverse arr shapeFn+ (\get (sh :. x) -> get (sh :. (x * 4 + 1)))++ arrBlue+ = traverse arr shapeFn+ (\get (sh :. x) -> get (sh :. (x * 4 + 2)))+ + in (arrRed, arrGreen, arrBlue)+++-- | Read a RGBA image from a BMP file.+-- In the result, the higher two dimensions are the height and width,+-- and the lower indexes the RGBA component of each pixel. +-- If the BMP read has no alpha channel then alpha of the resulting pixels is set to 255.+-- If anything goes wrong when loading the file then `Error`.+readImageFromBMP + :: FilePath+ -> IO (Either Error (Array DIM3 Word8))++readImageFromBMP filePath+ = do ebmp <- readBMP filePath+ case ebmp of+ Left err -> return $ Left err+ Right bmp -> return $ Right (readImageFromBMP' bmp)+ +readImageFromBMP' bmp+ = let (width, height) = bmpDimensions bmp+ arr = fromByteString (Z :. height :. width :. 4)+ $ unpackBMPToRGBA32 bmp+ in arr++++-- Write ------------------------------------------------------------------------------------------+-- | Write a matrix to a BMP file.+-- Negative values are discarded. Positive values are normalised to the maximum +-- value in the matrix and used as greyscale pixels.+writeMatrixToGreyscaleBMP + :: FilePath+ -> Array DIM2 Double+ -> IO ()++writeMatrixToGreyscaleBMP fileName arr+ = let arrNorm = normalisePositive01 arr++ scale :: Double -> Word8+ scale x = fromIntegral (truncate (x * 255) :: Int)++ arrWord8 = A.map scale arrNorm+ in writeComponentsToBMP fileName arrWord8 arrWord8 arrWord8+ ++-- | Write RGB components to a BMP file.+-- All arrays must have the same extent, else `error`.+writeComponentsToBMP+ :: FilePath+ -> Array DIM2 Word8+ -> Array DIM2 Word8+ -> Array DIM2 Word8+ -> IO ()++writeComponentsToBMP fileName arrRed arrGreen arrBlue+ | not $ ( extent arrRed == extent arrGreen + && extent arrGreen == extent arrBlue)+ = error "Data.Array.Repa.IO.BMP.writeComponentsToBMP: arrays don't have same extent"++ | otherwise+ = do let Z :. height :. width + = extent arrRed+ + -- Build image data from the arrays.+ let arrAlpha = fromFunction (extent arrRed) (\_ -> 255)+ let arrRGBA = interleave4 arrRed arrGreen arrBlue arrAlpha+ let bmp = packRGBA32ToBMP width height+ $ A.toByteString arrRGBA+ + writeBMP fileName bmp+++-- | Write a RGBA image to a BMP file.+-- The higher two dimensions are the height and width of the image. +-- The lowest dimension must have size 4, corresponding to the RGBA components+-- of each pixel, else `error`. +writeImageToBMP + :: FilePath+ -> Array DIM3 Word8+ -> IO ()++writeImageToBMP fileName arrImage+ | comps /= 4+ = error "Data.Array.Repa.IO.BMP: lowest order dimension must be 4"++ | otherwise+ = let bmp = packRGBA32ToBMP height width + $ A.toByteString arrImage+ in writeBMP fileName bmp+ + where Z :. height :. width :. comps + = extent arrImage+ ++-- Normalise --------------------------------------------------------------------------------------+-- | Normalise a matrix to to [0 .. 1], discarding negative values.+-- If the maximum value is 0 then return the array unchanged.+normalisePositive01+ :: (Shape sh, U.Elt a, Fractional a, Ord a)+ => Array sh a+ -> Array sh a++{-# INLINE normalisePositive01 #-}+normalisePositive01 arr + = let mx = foldAll max 0 arr+ elemFn x+ | x >= 0 = x / mx+ | otherwise = x+ in mx `seq`+ if mx == 0 + then arr+ else A.map elemFn arr+
+ Data/Array/Repa/IO/ColorRamp.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE RankNTypes #-}++-- | Hyprometric color ramps, for making pretty images from scalar data.+module Data.Array.Repa.IO.ColorRamp+ (rampColorHotToCold)+where++-- | Standard Hot to Cold hypsometric color ramp.+-- Color sequence is red, yellow, green, cyan, blue.+rampColorHotToCold + :: forall a+ . (Ord a, Floating a) + => a -- ^ Minimum value of range.+ -> a -- ^ Maximum value of range.+ -> a -- ^ Data value.+ -> (a, a, a)+ +{-# INLINE rampColorHotToCold #-}+rampColorHotToCold vmin vmax vNotNorm+ = let + v | vNotNorm < vmin = vmin+ | vNotNorm > vmax = vmax+ | otherwise = vNotNorm+ + dv = vmax - vmin ++ result | v < vmin + 0.25 * dv+ = ( 0+ , 4 * (v - vmin) / dv+ , 1.0)+ + | v < vmin + 0.5 * dv+ = ( 0+ , 1.0+ , 1 + 4 * (vmin + 0.25 * dv - v) / dv)+ + | v < vmin + 0.75 * dv+ = ( 4 * (v - vmin - 0.5 * dv) / dv+ , 1.0+ , 0.0)+ + | otherwise+ = ( 1.0+ , 1 + 4 * (vmin + 0.75 * dv - v) / dv+ , 0)+ + in result+
+ Data/Array/Repa/IO/Internals/Text.hs view
@@ -0,0 +1,41 @@+{-# OPTIONS_HADDOCK hide #-}+module Data.Array.Repa.IO.Internals.Text+ ( hWriteValues+ , readValues)+where+import System.IO+import Data.Char++-- Stuff shared with Matrix module -------------------------------------------------------------+-- | Write out values to a file.+hWriteValues+ :: Show a+ => Handle + -> [a] -- ^ Data values.+ -> IO ()++hWriteValues handle xx+ = go xx+ where go [] = return ()+ go (x:xs)+ = do hPutStr handle $ show x+ hPutStr handle $ "\n"+ go xs+++-- | Read a string containing ints separated by whitespace. +readValues :: (Num a, Read a) => String -> [a]+readValues cs = readValues' [] cs+ where readValues' _ [] = []+ readValues' acc (c : rest)+ | isSpace c+ = if null acc + then readValues' [] rest+ else read (reverse acc) : readValues' [] rest++ | isDigit c || c == '.' || c == 'e' || c == '-'+ = readValues' (c : acc) rest++ | otherwise+ = error $ "unexpected char in Matrix file " ++ show (ord c)+
+ Data/Array/Repa/IO/Matrix.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE PackageImports #-}+-- | Read and write matrices as ASCII text files.+--+-- The file format is like:+--+-- @+-- MATRIX -- header+-- 100 100 -- width and height+-- 1.23 1.56 1.23 ... -- data, separated by whitespace+-- ....+-- @+module Data.Array.Repa.IO.Matrix+ ( readMatrixFromTextFile+ , writeMatrixToTextFile)+where+import Data.Array.Repa.IO.Internals.Text+import Control.Monad+import System.IO+import Data.List as L+import Data.Array.Repa as A+import Prelude as P+import qualified "dph-prim-par" Data.Array.Parallel.Unlifted as U+++-- | Read a matrix from a text file.+--+-- WARNING: This doesn't do graceful error handling. If the file has the wrong format+-- you'll get a confusing `error`.+readMatrixFromTextFile+ :: (U.Elt a, Num a, Read a)+ => FilePath+ -> IO (Array DIM2 a) ++readMatrixFromTextFile fileName+ = do handle <- openFile fileName ReadMode+ + "MATRIX" <- hGetLine handle+ [width, height] <- liftM (P.map read . words) $ hGetLine handle+ str <- hGetContents handle+ let vals = readValues str++ let dims = Z :. width :. height+ let mat = fromList dims vals++ return mat+++-- | Write a matrix as a text file.+writeMatrixToTextFile + :: (U.Elt a, Show a)+ => FilePath+ -> Array DIM2 a+ -> IO ()++writeMatrixToTextFile fileName arr+ = do file <- openFile fileName WriteMode ++ hPutStrLn file "MATRIX"++ let Z :. width :. height + = extent arr++ hPutStrLn file $ show width ++ " " ++ show height+ + hWriteValues file $ toList arr+ hClose file+
+ Data/Array/Repa/IO/Vector.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE PackageImports #-}+-- | Read and write vectors as ASCII text files.+--+-- The file format is like:+--+-- @+-- VECTOR -- header+-- 100 -- length of vector+-- 1.23 1.56 1.23 ... -- data, separated by whitespace+-- ....+-- @+module Data.Array.Repa.IO.Vector+ ( readVectorFromTextFile+ , writeVectorToTextFile)+where+import Data.Array.Repa as A+import Data.Array.Repa.IO.Internals.Text+import Data.List as L+import Prelude as P+import System.IO+import Control.Monad+import Data.Char+import qualified "dph-prim-par" Data.Array.Parallel.Unlifted as U+++-- | Read a vector from a text file.+-- WARNING: This doesn't do graceful error handling. If the file has the wrong format+-- you'll get a confusing `error`.+readVectorFromTextFile+ :: (U.Elt a, Num a, Read a)+ => FilePath+ -> IO (Array DIM1 a) ++readVectorFromTextFile fileName+ = do handle <- openFile fileName ReadMode+ + "VECTOR" <- hGetLine handle+ [len] <- liftM (P.map readInt . words) $ hGetLine handle+ str <- hGetContents handle+ let vals = readValues str++ let dims = Z :. len+ let vec = fromList dims vals++ return vec++readInt :: String -> Int+readInt str+ | and $ P.map isDigit str+ = read str+ + | otherwise+ = error "Data.Array.Repa.IO.Vector.readVectorFromTextFile parse error when reading data"+ + +-- | Write a vector as a text file.+writeVectorToTextFile + :: (U.Elt a, Show a)+ => Array DIM1 a+ -> FilePath+ -> IO ()++writeVectorToTextFile arr fileName+ = do file <- openFile fileName WriteMode ++ hPutStrLn file "VECTOR"++ let Z :. len+ = extent arr++ hPutStrLn file $ show len+ hWriteValues file $ toList arr+ hClose file+ hFlush file+
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2010, University of New South Wales.+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 the University of New South Wales 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 ''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 COPYRIGHT HOLDERS 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
+ repa-io.cabal view
@@ -0,0 +1,40 @@+Name: repa-io+Version: 1.1.0.0+License: BSD3+License-file: LICENSE+Author: The DPH Team+Maintainer: Ben Lippmeier <benl@ouroborus.net>+Build-Type: Simple+Cabal-Version: >=1.6+Stability: experimental+Category: Data Structures+Homepage: http://trac.haskell.org/repa+Bug-reports: http://trac.haskell.org/repa/newticket+Description:+ NOTE: You must use the GHC head branch > 6.13.20100309 to get decent performance.+ Read and write Repa arrays in various formats.++Synopsis:+ Read and write Repa arrays in various formats.++Tested-with: GHC == 6.13.20100309, GHC == 6.12.1++Library+ Build-Depends: + base == 4.*,+ dph-prim-par == 0.4.*,+ repa == 1.1.*,+ repa-bytestring == 1.1.*,+ bmp == 1.1.*++ ghc-options:+ -Odph -Wall -fno-warn-missing-signatures++ Exposed-modules:+ Data.Array.Repa.IO.ColorRamp+ Data.Array.Repa.IO.BMP+ Data.Array.Repa.IO.Vector+ Data.Array.Repa.IO.Matrix+ + Other-modules:+ Data.Array.Repa.IO.Internals.Text