### Install JuicyPixels-extra with Stack Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Use this command to install the library using Stack. ```bash stack install JuicyPixels-extra ``` -------------------------------- ### Minimal Image Processing Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md This snippet demonstrates a basic workflow: reading an image, resizing it using bilinear interpolation, and saving the result. Ensure you have an 'input.png' file and the necessary libraries installed. ```haskell import Codec.Picture import Codec.Picture.Extra main :: IO () main = do Right (ImageRGB8 img) <- readImage "input.png" let scaled = scaleBilinear 300 300 img savePngImage "output.png" (ImageRGB8 scaled) ``` -------------------------------- ### Install JuicyPixels-extra with Cabal Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Use this command to install the library using Cabal. ```bash cabal install JuicyPixels-extra ``` -------------------------------- ### Minimal Image Resizing Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md A basic example demonstrating how to load, resize, and save an image using Codec.Picture.Extra. ```haskell {-# LANGUAGE OverloadedStrings #-} import Codec.Picture import Codec.Picture.Extra main :: IO () main = do -- Load image Right (ImageRGB8 img) <- readImage "input.png" -- Transform let result = scaleBilinear 300 300 img -- Save savePngImage "output.png" (ImageRGB8 result) ``` -------------------------------- ### Type-Directed Operations Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Shows how to create a square image with type-specific padding colors for RGB8 and RGBA8 pixel types. ```haskell -- Square with type-specific padding color squareRGB :: Image PixelRGB8 -> Image PixelRGB8 squareRGB = square (PixelRGB8 0 0 0) -- Black padding squareRGBA :: Image PixelRGBA8 -> Image PixelRGBA8 squareRGBA = square (PixelRGBA8 0 0 0 0) -- Transparent padding ``` -------------------------------- ### Generic Image Processor Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Demonstrates a function that works with any pixel type and its usage with specific image types. ```haskell import Codec.Picture import Codec.Picture.Extra -- A function that works with any pixel type processImage :: (Pixel a) => Image a -> Image a processImage = flipHorizontally . crop 10 10 100 100 -- Usage with specific types main :: IO () main = do Right (ImageRGB8 img) <- readImage "photo.png" let result = processImage img savePngImage "output.png" (ImageRGB8 result) ``` -------------------------------- ### Handle DynamicImage with Pattern Matching Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Example demonstrating how to read an image into a DynamicImage and then pattern match to handle specific pixel types like ImageRGB8. It scales the image and saves it, or prints an error message for unsupported types or read failures. ```haskell import Codec.Picture import Codec.Picture.Extra result <- readImage "photo.png" case result of Right (ImageRGB8 img) -> do let scaled = scaleBilinear 300 300 img savePngImage "scaled.png" (ImageRGB8 scaled) Right other -> putStrLn "Unsupported pixel type" Left err -> putStrLn $ "Read error: " ++ err ``` -------------------------------- ### Read and Scale Image with PixelRGB16 Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Example of reading a high-resolution PNG image and scaling it using bilinear interpolation. Assumes the image is of type ImageRGB16. ```haskell -- Used in Codec.Picture.Extra Right (ImageRGB16 img) <- readImage "hires-photo.png" let scaled = scaleBilinear 512 512 img ``` -------------------------------- ### Image Usage Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Demonstrates loading an image, accessing its dimensions, and constructing a new image manually. The Image type is central to image processing operations. ```haskell import Codec.Picture -- Load an image Right (ImageRGB8 img) <- readImage "photo.png" -- Type of img: Image PixelRGB8 let w = imageWidth img -- :: Int let h = imageHeight img -- :: Int -- Construct an image manually let newImg = generateImage (\x y -> PixelRGB8 x y 0) 100 100 -- Type of newImg: Image PixelRGB8 ``` -------------------------------- ### Example Usage of Safe Image Operations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Demonstrates how to use the safeScale function for image resizing and handles the case where scaling might fail due to invalid dimensions. Requires Codec.Picture and Codec.Picture.Extra. ```haskell import Codec.Picture import Codec.Picture.Extra -- Usage main :: IO () main = do Right (ImageRGB8 img) <- readImage "input.png" case safeScale 200 200 img of Just scaled -> savePngImage "output.png" (ImageRGB8 scaled) Nothing -> putStrLn "Invalid dimensions" ``` -------------------------------- ### PixelRGB8 Usage Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Illustrates creating black, white, and red PixelRGB8 values and using them with the `square` function for padding. PixelRGB8 is suitable for general image manipulation tasks. ```haskell let black = PixelRGB8 0 0 0 let white = PixelRGB8 255 255 255 let red = PixelRGB8 255 0 0 -- Used in Codec.Picture.Extra Right (ImageRGB8 img) <- readImage "photo.png" let padded = square (PixelRGB8 128 128 128) img -- Pad with gray ``` -------------------------------- ### Web API Endpoint for Generating Thumbnails Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md An example of a web API endpoint that generates a square thumbnail for an image, applying a background color and resizing. Returns the thumbnail as a PNG ByteString. Requires Codec.Picture and Codec.Picture.Extra. ```haskell -- Handle thumbnail request thumbnailEndpoint :: FilePath -> IO (Maybe ByteString) thumbnailEndpoint path = do result <- readImage path case result of Right (ImageRGB8 img) -> do let thumb = square (PixelRGB8 200 200 200) . scaleBilinear 128 128 $ img return $ Just (encodePng (ImageRGB8 thumb)) _ -> return Nothing ``` -------------------------------- ### Web API Endpoint for Image Resizing Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md An example of a web API endpoint that resizes an image to specified dimensions and returns the result as a PNG ByteString. Handles RGB8 images and returns Nothing on failure. Requires Codec.Picture and Codec.Picture.Extra. ```haskell -- Example structure for web API that serves images import Codec.Picture import Codec.Picture.Extra -- Handle image resize request resizeEndpoint :: Int -> Int -> FilePath -> IO (Maybe ByteString) resizeEndpoint w h path = do result <- readImage path case result of Right (ImageRGB8 img) -> do let scaled = scaleBilinear w h img return $ Just (encodePng (ImageRGB8 scaled)) _ -> return Nothing ``` -------------------------------- ### PixelRGBA8 Usage Example Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Shows the creation of transparent, opaque red, and semi-transparent PixelRGBA8 values. This type is used with functions like `trim` and `square` for image editing, particularly when alpha channels are involved. ```haskell let transparent = PixelRGBA8 0 0 0 0 let opaque_red = PixelRGBA8 255 0 0 255 let semi_transparent = PixelRGBA8 255 255 255 128 -- Used in Codec.Picture.Extra Right (ImageRGBA8 img) <- readImage "icon.png" let trimmed = trim img -- Removes transparent edges let squared = square (PixelRGBA8 0 0 0 0) img -- Pad with transparent pixels ``` -------------------------------- ### Run Tests with Stack Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md To run the comprehensive tests included in the library, use the `stack test` command. ```bash stack test ``` -------------------------------- ### Import JuicyPixels Types Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md All core types are available from the Codec.Picture module. ```haskell import Codec.Picture ``` -------------------------------- ### Add JuicyPixels-extra to Stack project Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Add the library to your stack.yaml file for dependency management. ```yaml extra-deps: - JuicyPixels-extra-0.6.0 ``` -------------------------------- ### Run Tests with Cabal Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md To run the comprehensive tests included in the library, use the `cabal test` command. ```bash cabal test ``` -------------------------------- ### Batch Image Resizing Workflow Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md This pattern shows how to resize multiple images in a directory using scaleBilinear. Ensure 'images' directory exists and 'resized' directory is writable. ```haskell import Codec.Picture import Codec.Picture.Extra import System.Directory (listDirectory) import System.FilePath (takeFileName, replaceExtension) resizeImages :: Int -> Int -> IO () resizeImages width height = do files <- listDirectory "images" mapM_ processFile files where processFile fname = do Right (ImageRGB8 img) <- readImage $ "images/" ++ fname let scaled = scaleBilinear width height img savePngImage ("resized/" ++ fname) (ImageRGB8 scaled) ``` -------------------------------- ### Batch Trim and Resize PNG Images from Directory Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Processes all PNG images in an input directory by auto-trimming transparent edges and resizing them to specified dimensions. The processed images are saved to an output directory. This is useful for batch image preparation tasks. ```haskell import Codec.Picture import Codec.Picture.Extra import System.Directory (listDirectory) -- Auto-trim all PNG images and resize to target size trimAndResizeBatch :: FilePath -> -- Input directory FilePath -> -- Output directory Int -> Int -> -- Target dimensions IO () trimAndResizeBatch inDir outDir w h = do files <- filter (".png" `isSuffixOf`) <$> listDirectory inDir mapM_ processFile files where processFile fname = do let inPath = inDir ++ "/" ++ fname Right (ImageRGBA8 img) <- readImage inPath let trimmed = trim img let resized = scaleBilinear w h trimmed let outPath = outDir ++ "/" ++ fname savePngImage outPath (ImageRGBA8 resized) isSuffixOf :: Eq a => [a] -> [a] -> Bool isSuffixOf suffix str = suffix == reverse (take (length suffix) (reverse str)) ``` -------------------------------- ### Add JuicyPixels-extra to Cabal Project Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md To add JuicyPixels-extra to your Cabal project, include it in the `build-depends` section of your `.cabal` file. ```cabal build-depends: JuicyPixels-extra >= 0.6 && < 0.7 ``` -------------------------------- ### Batch Process Icons with Auto-Trim and Resize Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Loads multiple icon images from specified file paths, applies auto-trimming and squaring, resizes them to 128x128, and arranges them into a single output image. This is ideal for creating sprite sheets or icon atlases. ```haskell import Codec.Picture import Codec.Picture.Extra -- Batch process icons with auto-trim processIcons :: [FilePath] -> FilePath -> IO () processIcons inPaths outPath = do images <- mapM loadAndProcess inPaths savePngImage outPath (ImageRGBA8 (beside images)) where loadAndProcess path = do Right (ImageRGBA8 img) <- readImage path return $ scaleBilinear 128 128 (trimAndSquare img) ``` -------------------------------- ### Add JuicyPixels-extra to Stack Project Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md To add JuicyPixels-extra to your Stack project, include it in the `dependencies` section of your `package.yaml` file. ```yaml dependencies: - JuicyPixels-extra >= 0.6.0 ``` -------------------------------- ### Chain Image Transformations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Demonstrates how to chain multiple image operations, such as scaling, rotating, and squaring, using function composition. This allows for complex image processing pipelines. ```haskell import Codec.Picture import Codec.Picture.Extra Right (ImageRGB8 img) <- readImage "original.png" -- Scale, then rotate, then add padding to square let result = square (PixelRGB8 255 255 255) . rotateRight90 . scaleBilinear 300 300 $ img savePngImage "transformed.png" (ImageRGB8 result) ``` -------------------------------- ### Batch Resize Images in a Directory Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Resizes all PNG images in a specified input directory to target dimensions and saves them to an output directory. It processes images sequentially and provides progress updates. ```haskell import Codec.Picture import Codec.Picture.Extra import System.Directory (listDirectory, createDirectoryIfMissing) import System.FilePath (takeFileName, replaceExtension, ()) import Control.Monad (forM_) -- Resize all PNG images in a directory batchResizeDirectory :: FilePath -> -- Input directory FilePath -> -- Output directory Int -> Int -> -- Target width and height IO () batchResizeDirectory inDir outDir w h = do createDirectoryIfMissing True outDir files <- filter isPNG <$> listDirectory inDir forM_ (zip [1..] files) $ \(i, file) -> do putStrLn $ "[" ++ show i ++ "/" ++ show (length files) ++ "] " ++ file let inPath = inDir file let outPath = outDir file result <- readImage inPath case result of Right (ImageRGB8 img) -> do let scaled = scaleBilinear w h img savePngImage outPath (ImageRGB8 scaled) Right _ -> putStrLn $ " Skipped (unsupported format)" Left err -> putStrLn $ " Error: " ++ err isPNG :: FilePath -> Bool isPNG path = takeExtension path == ".png" takeExtension :: FilePath -> String takeExtension = reverse . takeWhile (/= '.') . reverse ``` -------------------------------- ### Create a Contact Sheet Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Arranges multiple images into a flexible grid (contact sheet) with automatic sizing. Resizes images to a thumbnail width and arranges them per row. Requires helper `chunksOf`. ```haskell import Codec.Picture import Codec.Picture.Extra import Data.List (nub) -- Layout multiple images with automatic sizing contactSheet :: Int -> -- Desired thumbnail width Int -> -- Images per row [FilePath] -> -- Input file paths FilePath -> -- Output file path IO () contactSheet thumbWidth perRow paths outputPath = do -- Load and resize all images images <- loadImages paths let images' = map (scaleBilinear thumbWidth thumbWidth) images -- Group into rows let rows = chunksOf perRow images' -- Combine each row horizontally, then stack vertically let combined = below [beside row | row <- rows] savePngImage outputPath (ImageRGB8 combined) loadImages :: [FilePath] -> IO [Image PixelRGB8] loadImages paths = do results <- mapM readImage paths return [img | Right (ImageRGB8 img) <- results] chunksOf :: Int -> [a] -> [[a]] chunksOf _ [] = [] chunksOf n xs = take n xs : chunksOf n (drop n xs) ``` -------------------------------- ### Create Side-by-Side Before/After Comparison Image Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Combines two images (representing 'before' and 'after' states) into a single image placed side-by-side. Both input images are scaled to 256x256 before being combined. Useful for visual comparisons. ```haskell import Codec.Picture import Codec.Picture.Extra -- Create side-by-side comparison image beforeAfterComparison :: Image PixelRGB8 -> -- Before Image PixelRGB8 -> -- After Image PixelRGB8 -- Side-by-side beforeAfterComparison before after = beside [scaleBilinear 256 256 before, scaleBilinear 256 256 after] ``` -------------------------------- ### Create an Image Grid Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Combines multiple images into a specified N×M grid. Loads images, resizes them, and arranges them using `beside` and `below` functions. Requires helper `chunksOf`. ```haskell import Codec.Picture import Codec.Picture.Extra -- Load all images and ensure consistent size loadAndResize :: Int -> Int -> [FilePath] -> IO [Image PixelRGB8] loadAndResize w h paths = do results <- mapM readImage paths return [scaleBilinear w h img | Right (ImageRGB8 img) <- results] -- Create a 3×3 grid createGrid :: [FilePath] -> IO () createGrid paths = do -- Load 9 images, resize to 128×128 images <- loadAndResize 128 128 (take 9 paths) -- Split into rows of 3 let [row1, row2, row3] = chunksOf 3 images -- Combine rows horizontally, then stack vertically let grid = below [beside row1, beside row2, beside row3] savePngImage "grid.png" (ImageRGB8 grid) -- Helper function chunksOf :: Int -> [a] -> [[a]] chunksOf _ [] = [] chunksOf n xs = take n xs : chunksOf n (drop n xs) ``` -------------------------------- ### Thumbnail Creation with Padding Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Generates a square thumbnail of a specified size with a custom background color using scaleBilinear and square. The square function adds padding to make the image square. ```haskell import Codec.Picture import Codec.Picture.Extra makeThumbnail :: Int -> FilePath -> FilePath -> IO () makeThumbnail size inputPath outputPath = do Right (ImageRGB8 img) <- readImage inputPath let thumbnail = square (PixelRGB8 200 200 200) . scaleBilinear size size $ img savePngImage outputPath (ImageRGB8 thumbnail) ``` -------------------------------- ### Generate Multiple Thumbnail Sizes Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Generates multiple thumbnail sizes for a given input image. Each thumbnail is saved with a suffix indicating its size and a '.png' extension. ```haskell import Codec.Picture import Codec.Picture.Extra import System.FilePath (replaceExtension) -- Generate multiple thumbnail sizes from single image generateThumbnails :: FilePath -> -- Input image path [(Int, String)] -> -- [(size, suffix)] e.g. [(256, "256"), (128, "128")] IO () generateThumbnails inputPath sizeSpecs = do Right (ImageRGB8 img) <- readImage inputPath mapM_ (generateThumbnail img) sizeSpecs where generateThumbnail img (size, suffix) = do let scaled = scaleBilinear size size img let output = replaceExtension inputPath ("_" ++ suffix ++ ".png") savePngImage output (ImageRGB8 scaled) -- Usage main :: IO () main = generateThumbnails "photo.png" [ (512, "512") , (256, "256") , (128, "128") , (64, "64") ] ``` -------------------------------- ### Generic Pipeline Builder with Type Classes Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Build reusable transformation pipelines using type classes. This allows applying the same transformation logic to images of different pixel types. ```haskell import Codec.Picture import Codec.Picture.Extra -- Build reusable transformation pipelines class Transformer a where transform :: Image a -> Image a instance Transformer PixelRGB8 where transform = flipHorizontally . crop 50 50 300 300 . scaleBilinear 400 400 -- Usage: apply same transform to any pixel type applyTransform :: (Transformer a) => Image a -> Image a applyTransform = transform ``` -------------------------------- ### below Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Combines multiple images vertically, stacking them on top of each other. The resulting image's height is the sum of the input images' heights, and its width is the minimum of the input images' widths. ```APIDOC ## below ### Description Combines multiple images vertically, stacking them on top of each other. The resulting image's height is the sum of the input images' heights, and its width is the minimum of the input images' widths. ### Signature ```haskell below :: (Pixel a) => [Image a] -> Image a ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```haskell import Codec.Picture import Codec.Picture.Extra Right (ImageRGB8 img1) <- readImage "photo1.png" Right (ImageRGB8 img2) <- readImage "photo2.png" Right (ImageRGB8 img3) <- readImage "photo3.png" -- Create a vertical stack let combined = below [img1, img2, img3] savePngImage "strip-vertical.png" (ImageRGB8 combined) ``` ### Response #### Success Response (200) `Image a` — A new image with the minimum width of all input images and combined height (sum of input heights). #### Response Example None ``` -------------------------------- ### Resize Image with Bilinear Interpolation Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Loads an image, resizes it to specified dimensions using bilinear interpolation, and saves the result. Ensure the input image is in RGB8 format. ```haskell import Codec.Picture import Codec.Picture.Extra main :: IO () main = do -- Load image result <- readImage "photo.png" case result of Right (ImageRGB8 img) -> do -- Resize to 400×300 let resized = scaleBilinear 400 300 img -- Save result savePngImage "resized.png" (ImageRGB8 resized) Right other -> putStrLn "Unsupported format" Left err -> putStrLn $ "Error: " ++ err ``` -------------------------------- ### Property-Based Testing for Image Rotations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Verify that rotating an image left by 90 degrees and then right by 90 degrees results in the original image. This snippet requires the Codec.Picture and Codec.Picture.Extra libraries. ```haskell import Codec.Picture import Codec.Picture.Extra -- Verify rotation properties prop_rotateLeft90ThenRight90IsIdentity :: Image PixelRGB8 -> Bool prop_rotateLeft90ThenRight90IsIdentity img = imagesEqual img (rotateRight90 (rotateLeft90 img)) ``` -------------------------------- ### Image Batching Utility Functions Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Utility functions for loading and saving multiple images at once. Use these for batch processing tasks where you need to read or write a list of image files. ```haskell import Codec.Picture import Codec.Picture.Extra import Control.Monad (mapM) -- Load multiple images at once loadImages :: [FilePath] -> IO [Image PixelRGB8] loadImages paths = do results <- mapM readImage paths return [img | Right (ImageRGB8 img) <- results] -- Save multiple images saveImages :: [(Image PixelRGB8, FilePath)] -> IO () saveImages = mapM_ (uncurry savePngImage) ``` -------------------------------- ### Compare Images for Equality in Tests Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Compare two images for equality based on dimensions and pixel data. This is a fundamental utility for testing image processing functions. ```haskell import Codec.Picture import Codec.Picture.Extra import Foreign.Storable (Storable) -- Compare images for equality imagesEqual :: (Eq (PixelBaseComponent a), Storable (PixelBaseComponent a)) => Image a -> Image a -> Bool imagesEqual img1 img2 = (imageWidth img1 == imageWidth img2) && (imageHeight img1 == imageHeight img2) && (imageData img1 == imageData img2) -- Test transformation preserves dimensions assertDimensionsPreserved :: (Image PixelRGB8 -> Image PixelRGB8) -> Image PixelRGB8 -> Bool assertDimensionsPreserved transform img = let result = transform img in imageWidth img == imageWidth result && imageHeight img == imageHeight result ``` -------------------------------- ### Precompute Common Image Sizes with Caching Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Cache common image sizes to avoid recomputation. Use this pattern when multiple transformations require access to images of predefined, frequently used dimensions. ```haskell import Codec.Picture import Codec.Picture.Extra import Data.Map (Map, fromList, lookup) import Prelude hiding (lookup) -- Cache common sizes to avoid recomputation data ThumbnailCache = ThumbnailCache { thumb64 :: Image PixelRGB8 , thumb128 :: Image PixelRGB8 , thumb256 :: Image PixelRGB8 , full :: Image PixelRGB8 } makeCache :: Image PixelRGB8 -> ThumbnailCache makeCache img = ThumbnailCache { thumb64 = scaleBilinear 64 64 img , thumb128 = scaleBilinear 128 128 img , thumb256 = scaleBilinear 256 256 img , full = img } getThumbnail :: Int -> ThumbnailCache -> Image PixelRGB8 getThumbnail size cache | size <= 64 = thumb64 cache | size <= 128 = thumb128 cache | size <= 256 = thumb256 cache | otherwise = full cache ``` -------------------------------- ### Type-Safe Polymorphic Image Resizing Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Demonstrates a generic `resize` function using `scaleBilinear` that works with any `Pixel` type. A specialized `squareWithColor` wrapper is also shown. ```haskell import Codec.Picture import Codec.Picture.Extra -- Generic function that works with any pixel type resize :: (Pixel a) => Int -> Int -> Image a -> Image a resize = scaleBilinear -- Specialized wrapper with compile-time padding color squareWithColor :: (Pixel a) => a -> Image a -> Image a squareWithColor = square -- Usage main = do Right (ImageRGB8 img) <- readImage "photo.png" let resized = resize 200 200 img -- Type inferred as Image PixelRGB8 savePngImage "out.png" (ImageRGB8 resized) ``` -------------------------------- ### beside Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Combines multiple images horizontally, placing them side by side. The resulting image's width is the sum of the input images' widths, and its height is the minimum of the input images' heights. ```APIDOC ## beside ### Description Combines multiple images horizontally, placing them side by side. The resulting image's width is the sum of the input images' widths, and its height is the minimum of the input images' heights. ### Signature ```haskell beside :: (Pixel a) => [Image a] -> Image a ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```haskell import Codec.Picture import Codec.Picture.Extra Right (ImageRGB8 img1) <- readImage "photo1.png" Right (ImageRGB8 img2) <- readImage "photo2.png" Right (ImageRGB8 img3) <- readImage "photo3.png" -- Create a horizontal strip let combined = beside [img1, img2, img3] savePngImage "strip-horizontal.png" (ImageRGB8 combined) ``` ### Response #### Success Response (200) `Image a` — A new image with combined width (sum of input widths) and the minimum height of all input images. #### Response Example None ``` -------------------------------- ### Image Grid Assembly Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Assembles a grid of images from a list of file paths using beside and below. Assumes images are in RGB8 format. The helper function chunksOf divides a list into sublists of a given size. ```haskell import Codec.Picture import Codec.Picture.Extra createGrid :: [FilePath] -> FilePath -> IO () createGrid paths outputPath = do images <- mapM loadRGB8 paths let rows = chunksOf 3 images let rowImages = map beside rows let grid = below rowImages savePngImage outputPath (ImageRGB8 grid) where loadRGB8 path = do Right (ImageRGB8 img) <- readImage path return img chunksOf _ [] = [] chunksOf n xs = take n xs : chunksOf n (drop n xs) ``` -------------------------------- ### Generate Comparison Strip of Progressive Image Scales Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Creates a horizontal strip of images, where each image is a scaled version of the input image at a specified size. This is useful for visualizing how an image looks at different resolutions. ```haskell import Codec.Picture import Codec.Picture.Extra -- Show image at different scales progressiveScales :: Image PixelRGB8 -> -- Input image [Int] -> -- Sizes to show (e.g., [50, 100, 200, 400]) Image PixelRGB8 -- Comparison strip progressiveScales img sizes = beside [scaleBilinear size size img | size <- sizes] ``` -------------------------------- ### Trim Constraint Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/types.md Additionally requires that components support equality testing for detecting fully transparent pixels. ```haskell Pixel a, Eq (PixelBaseComponent a) ``` -------------------------------- ### Module Exports for Codec.Picture.Extra Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/README.md This module exports nine functions for image manipulation. All functions are polymorphic over pixel types. ```haskell module Codec.Picture.Extra ( scaleBilinear , crop , trim , flipHorizontally , flipVertically , rotateLeft90 , rotateRight90 , rotate180 , beside , below , square ) where ``` -------------------------------- ### Content-Aware Trimming and Squaring Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Trims fully transparent edges from an image using trim and then makes it square with padding using square. The padding color is fully transparent black. ```haskell trimAndSquare :: Image PixelRGBA8 -> Image PixelRGBA8 trimAndSquare img = let trimmed = trim img in square (PixelRGBA8 0 0 0 0) trimmed ``` -------------------------------- ### Create a 2x2 Grid of Rotated Image Variations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Generates a single image composed of a 2x2 grid, where each cell contains a version of the input image rotated by 0, 90, 180, and 270 degrees. The input image is first resized to 200x200. ```haskell import Codec.Picture import Codec.Picture.Extra -- Create 2×2 grid of rotated versions rotatedGrid :: Image PixelRGB8 -> Image PixelRGB8 rotatedGrid img = let size = 200 sized = scaleBilinear size size img rotated0 = sized rotated90 = rotateRight90 sized rotated180 = rotate180 sized rotated270 = rotateLeft90 sized in below [ beside [rotated0, rotated90] , beside [rotated180, rotated270] ] ``` -------------------------------- ### Scale Image with Bilinear Interpolation Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Scales an image to specified dimensions using bilinear interpolation. Ensure the input image is loaded and the desired output path is available. ```haskell import Codec.Picture import Codec.Picture.Extra -- Load an image Right (ImageRGB8 img) <- readImage "photo.png" -- Scale down to 200x200 pixels let scaled = scaleBilinear 200 200 img -- Write the result savePngImage "photo-scaled.png" (ImageRGB8 scaled) ``` -------------------------------- ### Build Lazy Image Transformation Pipelines Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Build a transformation pipeline without executing until needed. This is useful for composing multiple image operations that will be applied lazily. ```haskell import Codec.Picture import Codec.Picture.Extra -- Build transformation pipeline without executing until needed type ImageTransform = Image PixelRGB8 -> Image PixelRGB8 -- Compose multiple transformations buildPipeline :: [ImageTransform] -> ImageTransform buildPipeline = foldr (.) id -- Usage main :: IO () main = do Right (ImageRGB8 img) <- readImage "input.png" let transforms = [ scaleBilinear 300 300 , flipHorizontally , rotateRight90 ] let pipeline = buildPipeline transforms let result = pipeline img -- All transforms applied here savePngImage "output.png" (ImageRGB8 result) ``` -------------------------------- ### Chain Image Transformations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Applies a sequence of image transformations (horizontal flip, crop, resize) to an image loaded from a file. Assumes the input image is in RGB8 format. ```haskell import Codec.Picture import Codec.Picture.Extra main :: IO () main = do Right (ImageRGB8 img) <- readImage "input.png" -- Apply multiple transformations let result = flipHorizontally . crop 50 50 200 200 . scaleBilinear 300 300 $ img savePngImage "output.png" (ImageRGB8 result) ``` -------------------------------- ### Image Mirroring Utility Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Mirrors an image horizontally using flipHorizontally. This is a simple utility function for creating a mirror image. ```haskell -- Flip to mirror image mirror :: Image PixelRGB8 -> Image PixelRGB8 mirror = flipHorizontally ``` -------------------------------- ### Combine Images Vertically Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Use `below` to stack multiple images vertically. The combined image will have a height equal to the sum of the input images' heights and a width equal to the minimum width of all input images. Ensure all images share the same pixel type and that the input list is not empty. ```haskell import Codec.Picture import Codec.Picture.Extra Right (ImageRGB8 img1) <- readImage "photo1.png" Right (ImageRGB8 img2) <- readImage "photo2.png" Right (ImageRGB8 img3) <- readImage "photo3.png" -- Create a vertical stack let combined = below [img1, img2, img3] savePngImage "strip-vertical.png" (ImageRGB8 combined) ``` -------------------------------- ### Property-Based Testing for Image Trimming Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Ensure that trimming an image either reduces its dimensions or keeps them the same. This snippet requires the Codec.Picture and Codec.Picture.Extra libraries. ```haskell import Codec.Picture import Codec.Picture.Extra -- Verify trimming reduces or maintains size prop_trimReducesOrMaintainsSize :: Image PixelRGBA8 -> Bool prop_trimReducesOrMaintainsSize img = let trimmed = trim img in imageWidth trimmed <= imageWidth img && imageHeight trimmed <= imageHeight img ``` -------------------------------- ### Chain Image Processing Operations Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Defines a pipeline of image transformations including padding, resizing, mirroring, and cropping. This demonstrates functional composition for image manipulation. ```haskell import Codec.Picture import Codec.Picture.Extra pipeline :: Image PixelRGB8 -> Image PixelRGB8 pipeline = square (PixelRGB8 255 255 255) -- Pad to square . scaleBilinear 256 256 -- Resize . flipHorizontally -- Mirror . crop 50 50 300 300 -- Extract region main = do Right (ImageRGB8 img) <- readImage "input.png" savePngImage "output.png" (ImageRGB8 (pipeline img)) ``` -------------------------------- ### Pad Images to Be Square Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Pads non-square images with a specified background color to make them square using the `square` function. Useful for creating uniform thumbnails for galleries. ```haskell import Codec.Picture import Codec.Picture.Extra -- Pad non-square image with background color padToSquare :: PixelRGB8 -> Image PixelRGB8 -> Image PixelRGB8 padToSquare bgColor = square bgColor -- Apply to multiple images padImages :: [FilePath] -> PixelRGB8 -> IO [Image PixelRGB8] padImages paths bgColor = do results <- mapM readImage paths let images = [img | Right (ImageRGB8 img) <- results] return [padToSquare bgColor img | img <- images] -- Usage: Create uniform thumbnails for gallery main :: IO () main = do images <- padImages ["img1.png", "img2.png"] (PixelRGB8 200 200 200) let thumbs = map (scaleBilinear 256 256) images savePngImage "thumbnails.png" (ImageRGB8 (beside thumbs)) ``` -------------------------------- ### Safe Image Scaling with Dimension Checks Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Provides a safe way to scale an image, returning Nothing if the target dimensions are non-positive. This prevents errors from invalid scaling operations. Requires Codec.Picture and Codec.Picture.Extra. ```haskell import Codec.Picture import Codec.Picture.Extra -- Guard against edge cases safeScale :: Int -> Int -> Image PixelRGB8 -> Maybe (Image PixelRGB8) safeScale w h img | w <= 0 || h <= 0 = Nothing | otherwise = Just (scaleBilinear w h img) ``` -------------------------------- ### Manual Image Cropping with crop Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Use the crop function to extract a specific rectangular region from an image using explicit coordinates and dimensions. Boundaries are automatically clamped to the image limits. ```haskell crop :: Pixel a => Int -> Int -> Int -> Int -> Image a -> Image a ``` -------------------------------- ### Combine Images Horizontally Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Use `beside` to combine a list of images into a single horizontal strip. The resulting image's width is the sum of the input images' widths, and its height is the minimum height of all input images. All input images must have the same pixel type, and the list must not be empty. ```haskell import Codec.Picture import Codec.Picture.Extra Right (ImageRGB8 img1) <- readImage "photo1.png" Right (ImageRGB8 img2) <- readImage "photo2.png" Right (ImageRGB8 img3) <- readImage "photo3.png" -- Create a horizontal strip let combined = beside [img1, img2, img3] savePngImage "strip-horizontal.png" (ImageRGB8 combined) ``` -------------------------------- ### Auto-Trim Transparent Edges and Pad to Square Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Removes transparent borders from an image and then pads it to make it a square. This is useful for preparing icons or images that need a uniform aspect ratio. ```haskell import Codec.Picture import Codec.Picture.Extra -- Remove transparent edges and pad to square trimAndSquare :: Image PixelRGBA8 -> Image PixelRGBA8 trimAndSquare = square (PixelRGBA8 0 0 0 0) . trim ``` -------------------------------- ### Process Image Safely with Error Handling Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Reads an image, scales it, and saves it, catching potential read or processing errors. Handles unsupported pixel formats and general exceptions. ```haskell import Codec.Picture import Codec.Picture.Extra import Control.Exception (catch, SomeException) processImage :: FilePath -> Int -> Int -> IO (Either String ()) processImage inputPath w h = catch go handleError where go = do result <- readImage inputPath case result of Right (ImageRGB8 img) -> do let scaled = scaleBilinear w h img savePngImage (outputPath inputPath) (ImageRGB8 scaled) return $ Right () Right _ -> return $ Left "Unsupported pixel format" Left err -> return $ Left $ "Read error: " ++ err handleError :: SomeException -> IO (Either String ()) handleError e = return $ Left $ "Exception: " ++ show e outputPath input = "output/" ++ dropExtension (takeFileName input) ++ ".png" ``` -------------------------------- ### Convert Image to Square Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/api-reference.md Use the `square` function to convert an image into a perfect square by adding filler pixels. It supports both RGB and RGBA images, allowing for solid color or transparent padding. ```haskell import Codec.Picture import Codec.Picture.Extra -- With RGB images using black padding Right (ImageRGB8 img) <- readImage "rectangular-photo.png" let padded = square (PixelRGB8 0 0 0) img savePngImage "square-photo.png" (ImageRGB8 padded) -- With RGBA images using transparent padding Right (ImageRGBA8 img2) <- readImage "icon.png" let padded2 = square (PixelRGBA8 0 0 0 0) img2 savePngImage "square-icon.png" (ImageRGBA8 padded2) ``` -------------------------------- ### Add Watermark to a Grid of Images Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Arranges a list of images into a grid with a specified number of images per row and applies a watermark to each image. Note: The provided `addWatermark` function is a placeholder and does not actually composite the watermark. ```haskell import Codec.Picture import Codec.Picture.Extra -- Add a watermark to a grid of images watermarkGrid :: Image PixelRGB8 -> -- Watermark Int -> -- Images per row [Image PixelRGB8] -> -- Input images Image PixelRGB8 -- Output grid watermarkGrid watermark perRow images = let marked = map (addWatermark watermark) images rows = chunksOf perRow marked in below [beside row | row <- rows] -- Overlay watermark in corner (simplified: not actually overlaying) addWatermark :: Image PixelRGB8 -> Image PixelRGB8 -> Image PixelRGB8 addWatermark _ img = img -- In real code, use compositing ``` -------------------------------- ### Parallel Batch Image Processing with Worker Pool Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Processes a list of image input/output path pairs in parallel using a specified number of worker threads. This pattern is suitable for CPU-bound image processing tasks where concurrency can improve throughput. ```haskell import Codec.Picture import Codec.Picture.Extra import System.Directory (listDirectory) import Control.Concurrent (forkIO, newEmptyMVar, takeMVar, putMVar) import Control.Monad (replicateM_) -- Process images in parallel with worker pool batchResizeParallel :: Int -> -- Number of worker threads [(FilePath, FilePath)] -> -- [(input, output)] pairs Int -> Int -> -- Target dimensions IO () batchResizeParallel workers jobs w h = do -- Create job queue queue <- newMVar jobs -- Spawn workers mapM_ forkIO $ replicate workers (worker queue w h) -- Wait for all jobs to complete return () worker :: MVar [(FilePath, FilePath)] -> Int -> Int -> IO () worker queue w h = do job <- takeMVar queue case job of [] -> return () -- No more jobs ((inPath, outPath) : rest) -> do putMVar queue rest -- Process single image result <- readImage inPath case result of Right (ImageRGB8 img) -> do let scaled = scaleBilinear w h img savePngImage outPath (ImageRGB8 scaled) _ -> return () -- Process next job worker queue w h ``` -------------------------------- ### Safe Image Processing with Exception Handling Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Processes an image by resizing it, with robust error handling for file reading issues, unsupported formats, and general exceptions. Exits with failure code on error. ```haskell import Codec.Picture import Codec.Picture.Extra import Control.Exception (catch, SomeException) import System.Exit (exitFailure) processImage :: FilePath -> IO () processImage path = catch go handleError where go = do result <- readImage path case result of Right (ImageRGB8 img) -> savePngImage "output.png" (ImageRGB8 (scaleBilinear 200 200 img)) Right _ -> putStrLn "Unsupported pixel format" >> exitFailure Left err -> putStrLn ("Read error: " ++ err) >> exitFailure handleError :: SomeException -> IO () handleError e = putStrLn ("Exception: " ++ show e) >> exitFailure main :: IO () main = processImage "input.png" ``` -------------------------------- ### Vertical Image Composition with below Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/module-guide.md Combines multiple images vertically, stacking them one below the other. The resulting image's width is determined by the minimum width of the input images. ```haskell below :: Pixel a => [Image a] -> Image a ``` -------------------------------- ### Type-Specific Padding Functions Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Define type-specific padding functions for different image pixel types. Use these when you need to pad images with a specific color that matches the image's pixel type. ```haskell import Codec.Picture import Codec.Picture.Extra -- Type-specific padding color selection squareRGB :: Image PixelRGB8 -> Image PixelRGB8 squareRGB = square (PixelRGB8 0 0 0) -- Black squareRGBA :: Image PixelRGBA8 -> Image PixelRGBA8 squareRGBA = square (PixelRGBA8 0 0 0 0) -- Transparent squareWhiteRGB :: Image PixelRGB8 -> Image PixelRGB8 squareWhiteRGB = square (PixelRGB8 255 255 255) -- White -- Usage main :: IO () main = do Right (ImageRGB8 img) <- readImage "photo.png" savePngImage "squared.png" (ImageRGB8 (squareRGB img)) ``` -------------------------------- ### Property-Based Testing for Image Flips and Rotation Source: https://github.com/mrkkrp/juicypixels-extra/blob/master/_autodocs/examples-and-patterns.md Check if flipping an image horizontally and then vertically is equivalent to rotating it by 180 degrees. This snippet requires the Codec.Picture and Codec.Picture.Extra libraries. ```haskell import Codec.Picture import Codec.Picture.Extra -- Verify flip composition prop_flipBothIsRotate180 :: Image PixelRGB8 -> Bool prop_flipBothIsRotate180 img = imagesEqual (rotate180 img) (flipVertically (flipHorizontally img)) ```