packages feed

netpbm 0.3.0 → 1.0.0

raw patch · 3 files changed

+72/−35 lines, 3 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Graphics.Netpbm: PPMHeader :: PPMType -> Int -> Int -> PPMHeader
+ Graphics.Netpbm: PPMHeader :: !PPMType -> !Int -> !Int -> PPMHeader
- Graphics.Netpbm: pixelVectorToList :: Unbox a => Vector a -> [a]
+ Graphics.Netpbm: pixelVectorToList :: Storable a => Vector a -> [a]
- Graphics.Netpbm: ppmHeight :: PPMHeader -> Int
+ Graphics.Netpbm: ppmHeight :: PPMHeader -> !Int
- Graphics.Netpbm: ppmType :: PPMHeader -> PPMType
+ Graphics.Netpbm: ppmType :: PPMHeader -> !PPMType
- Graphics.Netpbm: ppmWidth :: PPMHeader -> Int
+ Graphics.Netpbm: ppmWidth :: PPMHeader -> !Int

Files

netpbm.cabal view
@@ -1,5 +1,5 @@ name:          netpbm-version:       0.3.0+version:       1.0.0 license:       MIT copyright:     2013 Niklas Hambüchen <mail@nh2.me> author:        Niklas Hambüchen <mail@nh2.me>@@ -18,7 +18,12 @@   All netpbm image formats are implemented (P1 - P6).   .   The current implementation parses PPM images at around 10 MB/s on a Core i5-2520M.-+  .+  CHANGELOG+  .+  Version 1.0.0+  .+  * Use storable instead of unboxed vectors to allow easier integration with Ptr based APIs.  source-repository head   type:      git@@ -56,6 +61,7 @@     , bytestring >= 0.9     , hspec >= 1.3.0.1     , HUnit >= 1.2+    , vector >= 0.7   ghc-options: -Wall  
src/Graphics/Netpbm.hs view
@@ -39,10 +39,9 @@ import           Foreign.Storable.Record as Store import           Foreign.Storable (Storable (..)) -import qualified Data.Vector.Unboxed as U-import           Data.Vector.Unboxed ((!))-import qualified Data.Vector.Generic-import qualified Data.Vector.Generic.Mutable as VGM+import qualified Data.Vector.Storable as S+import           Data.Vector.Storable ((!))+import qualified Data.Vector.Storable.Mutable as SM  import Data.Vector.Unboxed.Deriving @@ -63,10 +62,11 @@ , ppmData   :: PpmPixelData } +-- | Meta information about the image: The exact PPM format and dimensions. data PPMHeader = PPMHeader {-  ppmType   :: PPMType-, ppmWidth  :: Int-, ppmHeight :: Int+  ppmType   :: !PPMType+, ppmWidth  :: !Int+, ppmHeight :: !Int } deriving (Eq, Show)  instance Show PPM where@@ -101,27 +101,33 @@  -- | Image data, either 8 or 16 bits. -- TODO rename to PNM-data PpmPixelData = PpmPixelDataRGB8 (U.Vector PpmPixelRGB8)   -- ^ For 8-bit PPMs.-                  | PpmPixelDataRGB16 (U.Vector PpmPixelRGB16) -- ^ For 16-bit PPMs.-                  | PbmPixelData (U.Vector PbmPixel)           -- ^ For 1-bit PBMs.-                  | PgmPixelData8 (U.Vector PgmPixel8)         -- ^ For 8-bit PGMs.-                  | PgmPixelData16 (U.Vector PgmPixel16)       -- ^ For 16-bit PGMs.+data PpmPixelData = PpmPixelDataRGB8 (S.Vector PpmPixelRGB8)   -- ^ For 8-bit PPMs.+                  | PpmPixelDataRGB16 (S.Vector PpmPixelRGB16) -- ^ For 16-bit PPMs.+                  | PbmPixelData (S.Vector PbmPixel)           -- ^ For 1-bit PBMs.+                  | PgmPixelData8 (S.Vector PgmPixel8)         -- ^ For 8-bit PGMs.+                  | PgmPixelData16 (S.Vector PgmPixel16)       -- ^ For 16-bit PGMs.  -pixelVectorToList :: (U.Unbox a) => U.Vector a -> [a]-pixelVectorToList = U.toList+-- | Converts a vector of pixels to a list for convenience.+pixelVectorToList :: (Storable a) => S.Vector a -> [a]+pixelVectorToList = S.toList  +-- | Converts pixel data to a list of positive `Int`s.+--+-- How big they can become depends on the bit depth of the pixel data. pixelDataToIntList :: PpmPixelData -> [Int] pixelDataToIntList d = case d of-  PpmPixelDataRGB8 v  -> concat [ map fromIntegral [r, g, b] | PpmPixelRGB8 r g b  <- U.toList v ]-  PpmPixelDataRGB16 v -> concat [ map fromIntegral [r, g, b] | PpmPixelRGB16 r g b <- U.toList v ]-  PbmPixelData v      ->        [ if b then 1 else 0         | PbmPixel b          <- U.toList v ]-  PgmPixelData8 v     ->        [ fromIntegral x             | PgmPixel8 x         <- U.toList v ]-  PgmPixelData16 v    ->        [ fromIntegral x             | PgmPixel16 x        <- U.toList v ]+  PpmPixelDataRGB8 v  -> concat [ map fromIntegral [r, g, b] | PpmPixelRGB8 r g b  <- S.toList v ]+  PpmPixelDataRGB16 v -> concat [ map fromIntegral [r, g, b] | PpmPixelRGB16 r g b <- S.toList v ]+  PbmPixelData v      ->        [ if b then 1 else 0         | PbmPixel b          <- S.toList v ]+  PgmPixelData8 v     ->        [ fromIntegral x             | PgmPixel8 x         <- S.toList v ]+  PgmPixelData16 v    ->        [ fromIntegral x             | PgmPixel16 x        <- S.toList v ]   -- * Unbox instance for pixels+--+-- Not used internally, but an Unbox instance might be convenient for users.  derivingUnbox "PpmPixelRGB8"     [t| PpmPixelRGB8 -> (Word8, Word8, Word8) |]@@ -316,9 +322,9 @@   raster <- case maxColorVal of -- 1 or 2 bytes per pixel     -- Parse pixel data into vector, making sure that words don't exceed maxColorVal     m | m < 256   -> let v = word8max (fromIntegral m)-                      in PpmPixelDataRGB8  <$> U.replicateM (height * width) (PpmPixelRGB8  <$> v <*> v <*> v)+                      in PpmPixelDataRGB8  <$> S.replicateM (height * width) (PpmPixelRGB8  <$> v <*> v <*> v)     m | otherwise -> let v = word16max (fromIntegral m)-                      in PpmPixelDataRGB16 <$> U.replicateM (height * width) (PpmPixelRGB16 <$> v <*> v <*> v)+                      in PpmPixelDataRGB16 <$> S.replicateM (height * width) (PpmPixelRGB16 <$> v <*> v <*> v)    return $ PPM header raster @@ -338,9 +344,9 @@   raster <- case maxGreyVal of -- 1 or 2 bytes per pixel     -- Parse pixel data into vector, making sure that words don't exceed maxGreyVal     m | m < 256   -> let v = word8max (fromIntegral m)-                      in PgmPixelData8  <$> U.replicateM (height * width) (PgmPixel8  <$> v)+                      in PgmPixelData8  <$> S.replicateM (height * width) (PgmPixel8  <$> v)     m | otherwise -> let v = word16max (fromIntegral m)-                      in PgmPixelData16 <$> U.replicateM (height * width) (PgmPixel16 <$> v)+                      in PgmPixelData16 <$> S.replicateM (height * width) (PgmPixel16 <$> v)    return $ PPM header raster @@ -355,10 +361,10 @@   let widthBytes = (width + 7) // 8    -- Parse pixel data first in into a Word8 vector, then translate to a Bool vector, leaving the don't-cares at the end out.-  word8Vector <- U.replicateM (height * widthBytes) anyWord8+  word8Vector <- S.replicateM (height * widthBytes) anyWord8 -  let bits = U.create $ do-        v <- VGM.replicate (width * height) (PbmPixel False)+  let bits = S.create $ do+        v <- SM.replicate (width * height) (PbmPixel False)         forM_ [0..height-1] $ \row ->           forM_ [0..width-1] $ \col ->             let i            = row * width + col@@ -367,7 +373,7 @@              -- We negate (see "not"), because:              --   "1 is black, 0 is white."              -- Also, `testBit` indexes from the right (LSB).-             in VGM.write v i (PbmPixel . not $ (word8Vector ! i8) `testBit` (7 - bitN))+             in SM.write v i (PbmPixel . not $ (word8Vector ! i8) `testBit` (7 - bitN))         return v    return $ PPM header (PbmPixelData bits)@@ -391,7 +397,7 @@   --   "White space in the raster section is ignored."   -- Don't allow it *after* so that we can check if there is a whitespace between raster and optional junk.   -- I use `generateM` here instead of fromList . (`sepBy` [whitespace]) because I believe it's faster.-  bits <- U.replicateM n (A.takeWhile isSpace_w8 *> asciiBit)+  bits <- S.replicateM n (A.takeWhile isSpace_w8 *> asciiBit)    -- From the spec (who the heck can even come up with this):   --   "You can put any junk you want after the raster, if it starts with a white space character."@@ -428,8 +434,8 @@   -- TODO size-check the int by first putting it in Word64 and limiting decimal length   raster <- case maxGreyVal of -- 1 or 2 bytes per pixel     -- Parse pixel data into vector, making sure that words don't exceed maxGreyVal-    m | m < 256 -> PgmPixelData8  <$> U.replicateM n (A.takeWhile isSpace_w8 *> (PgmPixel8  <$> decimal))-    _           -> PgmPixelData16 <$> U.replicateM n (A.takeWhile isSpace_w8 *> (PgmPixel16 <$> decimal))+    m | m < 256 -> PgmPixelData8  <$> S.replicateM n (A.takeWhile isSpace_w8 *> (PgmPixel8  <$> decimal))+    _           -> PgmPixelData16 <$> S.replicateM n (A.takeWhile isSpace_w8 *> (PgmPixel16 <$> decimal))    option () (A.takeWhile1 isSpace_w8 *> takeLazyByteString *> pure ()) @@ -458,8 +464,8 @@   -- TODO size-check the int by first putting it in Word64 and limiting decimal length   raster <- case maxColorVal of -- 1 or 2 bytes per pixel     -- Parse pixel data into vector, making sure that words don't exceed maxColorVal-    m | m < 256 -> PpmPixelDataRGB8  <$> U.replicateM n (PpmPixelRGB8  <$> d8  <*> d8  <*> d8 )-    _           -> PpmPixelDataRGB16 <$> U.replicateM n (PpmPixelRGB16 <$> d16 <*> d16 <*> d16)+    m | m < 256 -> PpmPixelDataRGB8  <$> S.replicateM n (PpmPixelRGB8  <$> d8  <*> d8  <*> d8 )+    _           -> PpmPixelDataRGB16 <$> S.replicateM n (PpmPixelRGB16 <$> d16 <*> d16 <*> d16)    option () (A.takeWhile1 isSpace_w8 *> takeLazyByteString *> pure ()) @@ -539,3 +545,7 @@       Done rest images -> Right (images, Just rest)       Partial _        -> error "parsePPM bug: Got a partial result after end of input"       Fail _ cs e      -> Left $ e ++ "; contexts: " ++ show cs+++-- writePPM :: PPM -> ByteString+-- writePPM PPM { ppmHeader = PPMHeader { ppmType } }
test/Main.hs view
@@ -1,8 +1,12 @@ {-# LANGUAGE NamedFieldPuns, OverloadedStrings #-} -import qualified Data.ByteString as BS import           Control.Applicative import           Control.Monad+import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BSI+import qualified Data.Vector.Storable as S+import           Foreign.Ptr (castPtr)+import           Foreign.Marshal.Utils (copyBytes) import           Test.Hspec import           Test.HUnit @@ -311,6 +315,23 @@     parseTestFile "SIPI-convert-plain.pbm" "a file produced by convert" $       -- convert SIPI.tiff -compress none SIPI-convert-plain.pbm       checkSinglePPM P1 (256,256)+++  describe "In-memory format" $ do++    it "represents 8-bit images in rgbrgbrgb... format" $ do++      let d = PpmPixelDataRGB8 $ S.fromList [ PpmPixelRGB8 1 2 3+                                            , PpmPixelRGB8 4 5 6+                                            , PpmPixelRGB8 7 8 9 ]+      let PpmPixelDataRGB8 vec = d++      bs <- BSI.create 9 $ \bsPtrWord8 ->+        S.unsafeWith vec $ \ppmPixelRgb8Ptr ->+          copyBytes bsPtrWord8 (castPtr ppmPixelRgb8Ptr) 9++      bs `shouldBe` "\1\2\3\4\5\6\7\8\9"+  -- Some result data