packages feed

JuicyPixels 3.2.9 → 3.2.9.1

raw patch · 5 files changed

+89/−40 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Codec.Picture.Png: class PngPaletteSaveable a where encodePalettedPng = encodePalettedPngWithMetadata mempty
- Codec.Picture: encodePalettedPng :: Palette -> Image Pixel8 -> Either String ByteString
+ Codec.Picture: encodePalettedPng :: PngPaletteSaveable a => Image a -> Image Pixel8 -> Either String ByteString
- Codec.Picture.Png: encodePalettedPng :: Palette -> Image Pixel8 -> Either String ByteString
+ Codec.Picture.Png: encodePalettedPng :: PngPaletteSaveable a => Image a -> Image Pixel8 -> Either String ByteString
- Codec.Picture.Png: encodePalettedPngWithMetadata :: Metadatas -> Palette -> Image Pixel8 -> Either String ByteString
+ Codec.Picture.Png: encodePalettedPngWithMetadata :: PngPaletteSaveable a => Metadatas -> Image a -> Image Pixel8 -> Either String ByteString

Files

JuicyPixels.cabal view
@@ -1,5 +1,5 @@ Name:                JuicyPixels
-Version:             3.2.9
+Version:             3.2.9.1
 Synopsis:            Picture loading/serialization (in png, jpeg, bitmap, gif, tga, tiff and radiance)
 Description:
     <<data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADABAMAAACg8nE0AAAAElBMVEUAAABJqDSTWEL/qyb///8AAABH/1GTAAAAAXRSTlMAQObYZgAAAN5JREFUeF7s1sEJgFAQxFBbsAV72v5bEVYWPwT/XDxmCsi7zvHXavYREBDI3XP2GgICqBBYuwIC+/rVayPUAyAg0HvIXBcQoDFDGnUBgWQQ2Bx3AYFaRoBpAQHWb3bt2ARgGAiCYFFuwf3X5HA/McgGJWI2FdykCv4aBYzmKwDwvl6NVmUAAK2vlwEALK7fo88GANB6HQsAAAAAAAAA7P94AQCzswEAAAAAAAAAAAAAAAAAAICzh4UAO4zWAYBfRutHA4Bn5C69JhowAMGoBaMWDG0wCkbBKBgFo2AUAACPmegUST/IJAAAAABJRU5ErkJggg==>>
@@ -28,7 +28,7 @@ Source-Repository this
     Type:      git
     Location:  git://github.com/Twinside/Juicy.Pixels.git
-    Tag:       v3.2.9
+    Tag:       v3.2.9.1
 
 Flag Mmap
     Description: Enable the file loading via mmap (memory map)
README.md view
@@ -41,6 +41,8 @@         - 16bits greyscale (non interleaved)
         - 16bits RGB (non interleaved)
         - 16bits RGBA (non interleaved)
+        - 8bits RGB paletted image
+        - 8bits RGBA paletted image
 
     * Metadata (reading/writing)
         * in a tEXT chunk: 'Title', 'Description', 'Author', 'Copyright',
changelog view
@@ -1,6 +1,11 @@ Change log
 ==========
 
+v3.2.9.1 November 2017
+----------------------
+
+ * Feature: Paletted alpha png saving
+
 v3.2.9 November 2017
 ----------------------
 
src/Codec/Picture/Png.hs view
@@ -17,7 +17,8 @@ --
 -- The loader has been validated against the pngsuite (http://www.libpng.org/pub/png/pngsuite.html)
 module Codec.Picture.Png( -- * High level functions
-                          PngSavable( .. )
+                          PngSavable( .. ),
+                          PngPaletteSaveable( .. )
 
                         , decodePng
                         , decodePngWithMetadata
src/Codec/Picture/Png/Export.hs view
@@ -6,11 +6,10 @@ -- | Module implementing a basic png export, no filtering is applyed, but
 -- export at least valid images.
 module Codec.Picture.Png.Export( PngSavable( .. )
+                               , PngPaletteSaveable( .. )
                                , writePng
                                , encodeDynamicPng
                                , writeDynamicPng
-                               , encodePalettedPng
-                               , encodePalettedPngWithMetadata
                                ) where
 #if !MIN_VERSION_base(4,8,0)
 import Data.Monoid( mempty )
@@ -35,6 +34,42 @@ import Codec.Picture.Metadata( Metadatas )
 import Codec.Picture.VectorByteConversion( blitVector, toByteString )
 
+-- | Encode a paletted image into a png if possible.
+class PngPaletteSaveable a where
+  -- | Encode a paletted image as a color indexed 8-bit PNG.
+  -- the palette must have between 1 and 256 values in it.
+  -- Accepts `PixelRGB8` and `PixelRGBA8` as palette pixel type
+  encodePalettedPng :: Image a -> Image Pixel8 -> Either String Lb.ByteString
+  encodePalettedPng = encodePalettedPngWithMetadata mempty
+
+  -- | Equivalent to 'encodePalettedPng' but allow writing of metadatas.
+  -- See `encodePngWithMetadata` for the details of encoded metadatas
+  -- Accepts `PixelRGB8` and `PixelRGBA8` as palette pixel type
+  encodePalettedPngWithMetadata :: Metadatas -> Image a -> Image Pixel8 -> Either String Lb.ByteString
+
+instance PngPaletteSaveable PixelRGB8 where
+  encodePalettedPngWithMetadata metas pal img
+      | w <= 0 || w > 256 || h /= 1 = Left "Invalid palette"
+      | VS.any isTooBig $ imageData img =
+          Left "Image contains indexes absent from the palette"
+      | otherwise = Right $ genericEncodePng (Just pal) Nothing PngIndexedColor metas img
+        where w = imageWidth pal
+              h = imageHeight pal
+              isTooBig v = fromIntegral v >= w
+
+instance PngPaletteSaveable PixelRGBA8 where
+  encodePalettedPngWithMetadata metas pal img
+      | w <= 0 || w > 256 || h /= 1 = Left "Invalid palette"
+      | VS.any isTooBig $ imageData img =
+          Left "Image contains indexes absent from the palette"
+      | otherwise = Right $ genericEncodePng (Just opaquePalette) (Just alphaPal) PngIndexedColor metas img
+    where
+      w = imageWidth pal
+      h = imageHeight pal
+      opaquePalette = dropAlphaLayer pal
+      alphaPal = imageData $ extractComponent PlaneAlpha pal
+      isTooBig v = fromIntegral v >= w
+
 -- | Encode an image into a png if possible.
 class PngSavable a where
     -- | Transform an image into a png encoded bytestring, ready
@@ -126,41 +161,63 @@   , chunkCRC    = pngComputeCrc [pLTESignature, binaryData]
   , chunkData   = binaryData
   }
-   where binaryData = Lb.fromChunks [toByteString $ imageData pal]
+  where binaryData = Lb.fromChunks [toByteString $ imageData pal]
 
+preparePaletteAlpha :: VS.Vector Pixel8 -> PngRawChunk
+preparePaletteAlpha alphaPal = PngRawChunk
+  { chunkLength = fromIntegral $ VS.length alphaPal
+  , chunkType   = tRNSSignature
+  , chunkCRC    = pngComputeCrc [tRNSSignature, binaryData]
+  , chunkData   = binaryData
+  }
+  where binaryData = Lb.fromChunks [toByteString alphaPal]
+
+type PaletteAlpha = VS.Vector Pixel8
+
 genericEncodePng :: forall px. (Pixel px, PixelBaseComponent px ~ Word8)
-                 => Maybe Palette -> PngImageType -> Metadatas -> Image px
+                 => Maybe Palette
+                 -> Maybe PaletteAlpha
+                 -> PngImageType -> Metadatas -> Image px
                  -> Lb.ByteString
-genericEncodePng palette imgKind metas
+genericEncodePng palette palAlpha imgKind metas
                  image@(Image { imageWidth = w, imageHeight = h, imageData = arr }) =
   encode PngRawImage { header = hdr
                      , chunks = encodeMetadatas metas
-                              <> prependPalette palette
-                                    [ prepareIDatChunk imgEncodedData
-                                    , endChunk]}
-    where hdr = preparePngHeader image imgKind 8
-          zero = B.singleton 0
-          compCount = componentCount (undefined :: px)
+                              <> paletteChunk
+                              <> transpChunk
+                              <> [ prepareIDatChunk imgEncodedData
+                                 , endChunk
+                                 ]}
+  where
+    hdr = preparePngHeader image imgKind 8
+    zero = B.singleton 0
+    compCount = componentCount (undefined :: px)
 
-          prependPalette Nothing l = l
-          prependPalette (Just p) l = preparePalette p : l
+    paletteChunk = case palette of
+      Nothing -> []
+      Just p -> [preparePalette p]
 
-          lineSize = compCount * w
-          encodeLine line = blitVector arr (line * lineSize) lineSize
-          imgEncodedData = Z.compress . Lb.fromChunks
-                        $ concat [[zero, encodeLine line] | line <- [0 .. h - 1]]
+    transpChunk = case palAlpha of
+      Nothing -> []
+      Just p -> [preparePaletteAlpha p]
 
+    lineSize = compCount * w
+    encodeLine line = blitVector arr (line * lineSize) lineSize
+    imgEncodedData = Z.compress
+        . Lb.fromChunks
+        $ concat [[zero, encodeLine line] | line <- [0 .. h - 1]]
+
 instance PngSavable PixelRGBA8 where
-  encodePngWithMetadata = genericEncodePng Nothing PngTrueColourWithAlpha
+  encodePngWithMetadata = genericEncodePng Nothing Nothing PngTrueColourWithAlpha
 
 instance PngSavable PixelRGB8 where
-  encodePngWithMetadata = genericEncodePng Nothing PngTrueColour
+  encodePngWithMetadata = genericEncodePng Nothing Nothing PngTrueColour
 
 instance PngSavable Pixel8 where
-  encodePngWithMetadata = genericEncodePng Nothing PngGreyscale
+  encodePngWithMetadata = genericEncodePng Nothing Nothing PngGreyscale
 
 instance PngSavable PixelYA8 where
-  encodePngWithMetadata = genericEncodePng Nothing PngGreyscaleWithAlpha
+  encodePngWithMetadata = genericEncodePng Nothing Nothing PngGreyscaleWithAlpha
 
 instance PngSavable PixelYA16 where
   encodePngWithMetadata = genericEncode16BitsPng PngGreyscaleWithAlpha
@@ -180,22 +237,6 @@ writeDynamicPng path img = case encodeDynamicPng img of
         Left err -> return $ Left err
         Right b  -> Lb.writeFile path b >> return (Right True)
-
--- | Encode a paletted image as a color indexed 8-bit PNG.
--- the palette must have between 1 and 256 values in it.
-encodePalettedPng :: Palette -> Image Pixel8 -> Either String Lb.ByteString
-encodePalettedPng = encodePalettedPngWithMetadata mempty
-
--- | Equivalent to 'encodePalettedPng' but allow writing of metadatas.
-encodePalettedPngWithMetadata :: Metadatas -> Palette -> Image Pixel8 -> Either String Lb.ByteString
-encodePalettedPngWithMetadata metas pal img
-    | w <= 0 || w > 256 || h /= 1 = Left "Invalid palette"
-    | VS.any isTooBig $ imageData img =
-        Left "Image contains indexes absent from the palette"
-    | otherwise = Right $ genericEncodePng (Just pal) PngIndexedColor metas img
-      where w = imageWidth pal
-            h = imageHeight pal
-            isTooBig v = fromIntegral v >= w
 
 -- | Encode a dynamic image in PNG if possible, supported images are:
 --