JuicyPixels-repa (empty) → 0.1
raw patch · 4 files changed
+346/−0 lines, 4 filesdep +JuicyPixelsdep +basedep +bytestringsetup-changed
Dependencies added: JuicyPixels, base, bytestring, repa, vector
Files
- Codec/Picture/Repa.hs +252/−0
- JuicyPixels-repa.cabal +62/−0
- LICENSE +30/−0
- Setup.hs +2/−0
+ Codec/Picture/Repa.hs view
@@ -0,0 +1,252 @@+{-# LANGUAGE EmptyDataDecls, FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-}+module Codec.Picture.Repa+ ( -- * Primitive types and operations+ Img, imgData+ , convertImage+ -- * Generic interface+ , readImage, decodeImage+ -- * Monomorphic image decoding functions+ , readImageRGBA, readImageRGB, readImageR, readImageG, readImageB+ , decodeImageRGBA, decodeImageRGB, decodeImageR, decodeImageG, decodeImageB+ -- * Image Representations (Phantom Types)+ , RGBA, RGB, R, G, B+ -- * Helper Functions (useful for OpenGL etc.) + , toVector+ , toForeignPtr+ , reverseColorChannel+ , flipHorizontally, flipVertically+ -- * Internal Functionallity (exported for advanced uses)+ , ToRGBAChannels(..)+ ) where+import qualified Data.Array.Repa as R+import Data.Array.Repa ((:.), Array, (:.)(..), Z(..), DIM3, backpermute, extent)+import qualified Codec.Picture as P+import Codec.Picture hiding (readImage, decodeImage)+import Codec.Picture.Types hiding (convertImage)+import qualified Data.Vector.Storable as S+import qualified Data.Vector.Unboxed as VU+import Foreign.ForeignPtr+import Data.Word+import Control.Monad+import Data.ByteString as B++-- |An all-red image+data R++-- |An all-green image+data G++-- |An all-blue image+data B++-- |A 32-bit image with full red, green, blue and alpha channels.+--+-- The image is stored as Height x Width x ColorChannel.+--+-- The color channel is stored in RGBA order. For the common OpenGL ordering+-- users might want to use 'reverseColorChannel'.+data RGBA++-- |A 24-bit image with red, green and blue channels+data RGB++-- |@Img a@ is an image where the phantom type 'a' indicates the image format+--+-- All images are held in a three dimensional 'repa' array. If the image+-- format is only two dimensional (ex: R, G, or B) then the shape is @Z :. y :. x :. 1@.+data Img a = Img { imgData :: Array DIM3 Word8 }++-- |By default, the color channel for 'RGBA' indexes 0 -> R, 1 -> G, 2+-- -> B, 3 -> A. This is the AGBR byte ordering in OpenGL. For+-- rendering with OpenGL's RGBA PixelFormat be sure to call+-- reverseColorChannel before converting to a Vector (or directly to+-- bytestring via 'repa-bytestring').+reverseColorChannel :: Img a -> Img a+reverseColorChannel (Img r) = Img (R.backpermute e order r)+ where+ e@(Z :. row :. col :. z) = R.extent r+ order (Z :. r :. c :. z') = Z :. r :. c :. z - z' - 1++readImageRGBA :: FilePath -> IO (Either String (Img RGBA))+readImageRGBA = readImage++readImageRGB :: FilePath -> IO (Either String (Img RGB))+readImageRGB = readImage++readImageB :: FilePath -> IO (Either String (Img B))+readImageB = readImage++readImageG :: FilePath -> IO (Either String (Img G))+readImageG = readImage++readImageR :: FilePath -> IO (Either String (Img R))+readImageR = readImage++decodeImageRGBA :: ByteString -> Either String (Img RGBA)+decodeImageRGBA = decodeImage++decodeImageRGB :: ByteString -> Either String (Img RGB)+decodeImageRGB = decodeImage++decodeImageR :: ByteString -> Either String (Img R)+decodeImageR = decodeImage++decodeImageG :: ByteString -> Either String (Img G)+decodeImageG = decodeImage++decodeImageB :: ByteString -> Either String (Img B)+decodeImageB = decodeImage++class DecodeImage a where+ decodeImage :: ByteString -> Either String (Img a)++instance DecodeImage RGBA where+ decodeImage = decodeImageRGBA+instance DecodeImage RGB where+ decodeImage = decodeImageRGB+instance DecodeImage R where+ decodeImage = decodeImageR+instance DecodeImage G where+ decodeImage = decodeImageG+instance DecodeImage B where+ decodeImage = decodeImageB++readImage :: DecodeImage a => FilePath -> IO (Either String (Img a))+readImage f = liftM decodeImage (B.readFile f)++-- | O(n) returning (pointer, length, offset)+toForeignPtr :: Img RGBA -> (ForeignPtr Word8, Int, Int)+toForeignPtr = S.unsafeToForeignPtr . S.convert . R.toVector . imgData++-- |Convert an 'Img' to a storable 'Vector', often useful for OpenGL+-- and other C interfaces. Notice the format of the data depends on+-- the type of the 'Img a'. O(n)+toVector :: Img a -> S.Vector Word8+toVector (Img a) = S.convert (R.toVector a)++-- Helper functions --+getChannel :: Int -> PixelRGBA8 -> Word8+getChannel 0 (PixelRGBA8 r g b a) = r+getChannel 1 (PixelRGBA8 r g b a) = g+getChannel 2 (PixelRGBA8 r g b a) = b+getChannel _ (PixelRGBA8 r g b a) = a++-- |For any of the JuicyPixel pixels, get the RGBA values+getChan :: (ToRGBAChannels p) => Int -> p -> Word8+getChan c = getChannel c . toRGBAChannels++-- |For any of the JuicyPixel images, get a channel of a particular pixel+getPixel :: (ToRGBAChannels p, Pixel p) => Int -> Int -> Int -> Image p -> Word8+getPixel x y z p = getChan z (pixelAt p x y)++-- Helper class and instances+class ToRGBAChannels a where+ toRGBAChannels :: a -> PixelRGBA8++instance ToRGBAChannels PixelRGBA8 where+ toRGBAChannels = id++instance ToRGBAChannels PixelYCbCr8 where+ toRGBAChannels = promotePixel . (id :: PixelRGB8 -> PixelRGB8) . convertPixel++instance ToRGBAChannels PixelRGB8 where+ toRGBAChannels = promotePixel++instance ToRGBAChannels PixelYA8 where+ toRGBAChannels = promotePixel+ +instance ToRGBAChannels Pixel8 where+ toRGBAChannels = promotePixel++zeroCopyConvert :: Int -> Image a -> Img b+zeroCopyConvert cc (Image w h dat) =+ let (ptr,off,len) = S.unsafeToForeignPtr dat+ sh = Z :. h :. w :. cc+ in if off == 0+ then flipVertically . Img . R.unsafeFromForeignPtr sh $ ptr+ else flipVertically . Img . R.fromVector sh $ VU.convert $ dat++-- Now we start the instances needing exported++-- |Converts from 'JuicyPixels' type to the repa-based 'Img' type.+class ConvertImage a b where+ -- |Converts from 'JuicyPixels' type (Usually 'Image' or+ -- 'DynamicImage' to the repa-based 'Img' type.+ convertImage :: a -> Img b++instance ConvertImage DynamicImage RGBA where+ convertImage (ImageY8 i) = convertImage i+ convertImage (ImageYA8 i) = convertImage i+ convertImage (ImageRGB8 i) = convertImage i+ convertImage (ImageRGBA8 i) = zeroCopyConvert 4 i+ convertImage (ImageYCbCr8 i) = convertImage i+ +instance ConvertImage DynamicImage RGB where+ convertImage (ImageY8 i) = convertImage i+ convertImage (ImageYA8 i) = convertImage i+ convertImage (ImageRGB8 i) = zeroCopyConvert 3 i+ convertImage (ImageRGBA8 i) = convertImage i+ convertImage (ImageYCbCr8 i) = convertImage i+ +instance ConvertImage DynamicImage R where+ convertImage (ImageY8 i) = convertImage i+ convertImage (ImageYA8 i) = convertImage i+ convertImage (ImageRGB8 i) = convertImage i+ convertImage (ImageRGBA8 i) = convertImage i+ convertImage (ImageYCbCr8 i) = convertImage i+ +instance ConvertImage DynamicImage G where+ convertImage (ImageY8 i) = convertImage i+ convertImage (ImageYA8 i) = convertImage i+ convertImage (ImageRGB8 i) = convertImage i+ convertImage (ImageRGBA8 i) = convertImage i+ convertImage (ImageYCbCr8 i) = convertImage i+ +instance ConvertImage DynamicImage B where+ convertImage (ImageY8 i) = convertImage i+ convertImage (ImageYA8 i) = convertImage i+ convertImage (ImageRGB8 i) = convertImage i+ convertImage (ImageRGBA8 i) = convertImage i+ convertImage (ImageYCbCr8 i) = convertImage i++instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) RGBA where+ convertImage p@(Image w h dat) =+ let z = 4+ in Img $ R.fromFunction (Z :. h :. w :. z) + (\(Z :. y :. x :. z') -> getPixel x y (z - z' - 1) p)+ +instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) RGB where+ convertImage p@(Image w h dat) =+ let z = 3+ in Img $ R.fromFunction (Z :. h :. w :. z)+ (\(Z :. y :. x :. z') -> getPixel x y (z' - z -1) p)++instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) R where+ convertImage p@(Image w h dat) =+ let z = 1+ in Img $ R.fromFunction (Z :. h :. w :. z)+ (\(Z :. y :. x :. z) -> getPixel x y 0 p)+ +instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) G where+ convertImage p@(Image w h dat) =+ let z = 1+ in Img $ R.fromFunction (Z :. h :. w :. z)+ (\(Z :. y :. x :. z) -> getPixel x y 1 p)+ +instance (ToRGBAChannels a, Pixel a) => ConvertImage (Image a) B where+ convertImage p@(Image w h dat) =+ let z = 1+ in Img $ R.fromFunction (Z :. h :. w :. z)+ (\(Z :. y :. x :. z) -> getPixel x y 2 p)++flipVertically :: Img a -> Img a+flipVertically (Img rp) = Img (backpermute e order rp)+ where+ e@(Z :. row :. col :. z) = extent rp+ order (Z :. oldRow :. oldCol :. oldChan) = Z :. row - oldRow - 1 :. oldCol :. oldChan++flipHorizontally :: Img a -> Img b+flipHorizontally (Img rp) = Img (backpermute e order rp)+ where+ e@(Z :. row :. col :. z) = extent rp+ order (Z :. oldRow :. oldCol :. oldChan) = Z :. oldRow :. col - oldCol - 1 :. oldChan
+ JuicyPixels-repa.cabal view
@@ -0,0 +1,62 @@+-- Juicy.Pixels.Interface.cabal auto-generated by cabal init. For+-- additional options, see+-- http://www.haskell.org/cabal/release/cabal-latest/doc/users-guide/authors.html#pkg-descr.+-- The name of the package.+Name: JuicyPixels-repa++-- The package version. See the Haskell package versioning policy+-- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for+-- standards guiding when and how versions should be incremented.+Version: 0.1++-- A short (one-line) description of the package.+Synopsis: Convenience functions to obtain array representations of images.++-- A longer description of the package.+Description: This wraps the Juicy.Pixels library to convert into 'Repa' and + 'Data.Vector.Storable' formats.++-- The license under which the package is released.+License: BSD3++-- The file containing the license text.+License-file: LICENSE++-- The package author(s).+Author: Thomas M. DuBuisson++-- An email address to which users can send suggestions, bug reports,+-- and patches.+Maintainer: Thomas.DuBuisson@gmail.com++-- A copyright notice.+-- Copyright: ++Category: Graphics++Build-type: Simple++-- Extra files to be distributed with the package, such as examples or+-- a README.+-- Extra-source-files: ++-- Constraint on the version of Cabal needed to build this package.+Cabal-version: >=1.6+++Library+ -- Modules exported by the library.+ Exposed-modules: Codec.Picture.Repa+ + -- Packages needed in order to build this package.+ Build-depends: base >= 4.0 && < 5, repa >= 2.1 && < 2.3+ , JuicyPixels >= 1.1 && < 1.2+ , vector >= 0.9 && < 0.10+ , bytestring >= 0.9 && < 0.10+ + -- Modules not exported by this package.+ -- Other-modules: + + -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.+ -- Build-tools: +
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2012, Thomas M. DuBuisson++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 Thomas M. DuBuisson 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.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain