Copyright | (c) 2016, M J Oldfield |
---|---|
Stability | Experimental |
Safe Haskell | None |
Language | Haskell2010 |
Toy.JuicyPixels
Description
Rationale
Juicy Pixels is a great package for loading and saving images, and I often use it in little command line tools for munging images. However, over time I find those scripts have rather too much common code for comfort.
This module is an attempt to abstract that common boilerplate code.
Examples
Here is the complete source for a program to reverse the bit-order of each image on the command line. For example, foo.gif will be bit-reversed and saved as foo-f.png
import Toy.JuicyPixels import Codec.Picture import Data.Word import Data.Bits import qualified Data.List as L main = transformImagesInArgsPNG flipImage (++ "-f") flipImage :: ImageRGB8 -> ImageRGB8 flipImage = pixelMap (liftRGB flipByte) flipByte :: Word8 -> Word8 flipByte = memoizeWord8 flipByte' flipByte' :: Word8 -> Word8 flipByte' x = L.foldl' setBit 0 $ [ 7 - i | i <- [0..7], testBit x i ]
The next example illustrates writing to stdout rather than files. It prints the frequency with which pixels are seen in each image on the command line: the results are essentially useless for photos, but perhaps useful with little icons.
import Toy.JuicyPixels import Codec.Picture import qualified Data.List as L import Text.Printf main = describeImagesInArgs countPixels countPixels :: ImageRGB8 -> String countPixels = concatMap pp . freqs . pixelList freqs :: (Ord a, Eq a) => [a] -> [(a,Int)] freqs = map (ps -> (head ps, length ps)) . L.group . L.sort pp (PixelRGB8 r g b, n) = printf "%3d %3d %3d: %8dn" r g b n
- type ImageRGB8 = Image PixelRGB8
- loadImage :: FilePath -> IO (Either String ImageRGB8)
- loadImageThen :: (ImageRGB8 -> IO ()) -> FilePath -> IO ()
- transformImagePNG :: (ImageRGB8 -> ImageRGB8) -> (String -> String) -> FilePath -> IO ()
- transformImagesInArgsPNG :: (ImageRGB8 -> ImageRGB8) -> (String -> String) -> IO ()
- transformImagePNG' :: (ImageRGB8 -> ImageRGB8) -> FilePath -> IO ()
- transformImage :: (FilePath -> a -> IO ()) -> String -> (ImageRGB8 -> a) -> (String -> String) -> FilePath -> IO ()
- transformImagesInArgs :: (FilePath -> a -> IO ()) -> String -> (ImageRGB8 -> a) -> (String -> String) -> IO ()
- describeImage :: Show a => (ImageRGB8 -> a) -> FilePath -> IO ()
- describeImagesInArgs :: Show a => (ImageRGB8 -> a) -> IO ()
- iPixelList :: ImageRGB8 -> [(Int, Int, PixelRGB8)]
- pixelList :: ImageRGB8 -> [PixelRGB8]
- liftRGB :: (Word8 -> Word8) -> PixelRGB8 -> PixelRGB8
- memoizeWord8 :: (Word8 -> Word8) -> Word8 -> Word8
Documentation
loadImage :: FilePath -> IO (Either String ImageRGB8) Source
loadImage
is just like readImage in Codec.Picture but
it forces the pixel type to PixelRGB8.
loadImageThen :: (ImageRGB8 -> IO ()) -> FilePath -> IO () Source
loadImageThen
loads an image, and, if successful invokes
the supplied handler. Said handler should return an IO action.
transformImagePNG :: (ImageRGB8 -> ImageRGB8) -> (String -> String) -> FilePath -> IO () Source
transformImagePNG
is just transformImage
specialized for
writing PNG files.
transformImagesInArgsPNG :: (ImageRGB8 -> ImageRGB8) -> (String -> String) -> IO () Source
transformImagesInArgsPNG
is just transformImagesInArgs
specialized for
writing PNG files.
transformImagePNG' :: (ImageRGB8 -> ImageRGB8) -> FilePath -> IO () Source
transformImagePNG'
is just transformImagePNG
where the output basename is just the input
with -x appended.
transformImage :: (FilePath -> a -> IO ()) -> String -> (ImageRGB8 -> a) -> (String -> String) -> FilePath -> IO () Source
transformImage
takes a function which saves something, a suitable
suffix for the file in which something is saved, a function for
making a something from an Image, a function for transforming the
basename, and finally the name of a file to transform.
This apparently bizarre API is useful to make transformers by
specifying the first four arguments to leave a FilePath -> IO ()
signature remaining.
The first two arguments specify how to save the result. The next specify the transformation: both the image data and to the file's basename.
A version specialized to saving PNG files is included: transformImagePNG
.
transformImagesInArgs :: (FilePath -> a -> IO ()) -> String -> (ImageRGB8 -> a) -> (String -> String) -> IO () Source
transformArgsAsImages
maps transformImage
over all the command
line arguments.
describeImagesInArgs :: Show a => (ImageRGB8 -> a) -> IO () Source
iPixelList :: ImageRGB8 -> [(Int, Int, PixelRGB8)] Source
iPixelList
turns an image into a list of (x,y,pixel) tuples.
liftRGB :: (Word8 -> Word8) -> PixelRGB8 -> PixelRGB8 Source
liftRGB
turns a byte transform to a PixelRGB8 transform
by applying the byte transform to all the components independently.
memoizeWord8 :: (Word8 -> Word8) -> Word8 -> Word8 Source
Given a byte transform, memoizeWord8
returns a functionally
identical transform which replaces calculation by an unboxed array
lookup. Hopefully this will be much faster.