flac-picture (empty) → 0.1.0
raw patch · 11 files changed
+324/−0 lines, 11 filesdep +JuicyPixelsdep +basedep +bytestringsetup-changedbinary-added
Dependencies added: JuicyPixels, base, bytestring, data-default-class, directory, flac, flac-picture, hspec, temporary
Files
- CHANGELOG.md +3/−0
- Codec/Audio/FLAC/Metadata/Picture.hs +73/−0
- LICENSE.md +28/−0
- README.md +17/−0
- Setup.hs +6/−0
- audio-samples/sample.flac binary
- flac-picture.cabal +91/−0
- picture-samples/lenna.jpeg binary
- picture-samples/lenna.png binary
- tests/Codec/Audio/FLAC/Metadata/PictureSpec.hs +105/−0
- tests/Spec.hs +1/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## FLAC Picture 0.1.0++* Initial release.
+ Codec/Audio/FLAC/Metadata/Picture.hs view
@@ -0,0 +1,73 @@+-- |+-- Module : Codec.Audio.FLAC.Metadata.Picture+-- Copyright : © 2017 Mark Karpov+-- License : BSD 3 clause+--+-- Maintainer : Mark Karpov <markkarpov@openmailbox.org>+-- Stability : experimental+-- Portability : portable+--+-- Juicy-Pixels-powered helpers to read\/write images to FLAC metadata+-- blocks. For maximal player support, use PNG or JPEG (we don't provide+-- helpers for other formats at the time anyway).++{-# LANGUAGE OverloadedStrings #-}++module Codec.Audio.FLAC.Metadata.Picture+ ( retrieveImage+ , writeJpegPicture+ , writePngPicture )+where++import Codec.Audio.FLAC.Metadata+import Codec.Picture+import Data.Word+import qualified Data.ByteString.Lazy as BL++-- | Read specific picture from FLAC metadata as 'DynamicImage'.++retrieveImage+ :: PictureType+ -> FlacMeta (Either String DynamicImage)+retrieveImage pictureType = do+ mpicture <- retrieve (Picture pictureType)+ case mpicture of+ Nothing -> return (Left "Picture not found")+ Just picture -> (return . decodeImage . pictureData) picture++-- | Write the given image into FLAC metadata block corresponding to+-- specific 'PictureType'.++writeJpegPicture+ :: PictureType -- ^ Type of picture we're writing+ -> Word8 -- ^ Quality factor, see 'encodeJpegAtQuality'+ -> Image PixelYCbCr8 -- ^ The picture to write+ -> FlacMeta ()+writeJpegPicture pictureType q image =+ Picture pictureType =-> Just PictureData+ { pictureMimeType = "image/jpeg"+ , pictureDescription = ""+ , pictureWidth = fromIntegral (imageWidth image)+ , pictureHeight = fromIntegral (imageHeight image)+ , pictureDepth = 24+ , pictureColors = 0 -- non-indexed+ , pictureData = BL.toStrict (encodeJpegAtQuality q image)+ }++-- | Write the given image into FLAC metadata block corresponding to+-- specific 'PictureType'.++writePngPicture+ :: PictureType -- ^ Type of picture we're writing+ -> Image PixelRGB8 -- ^ The picture to write+ -> FlacMeta ()+writePngPicture pictureType image =+ Picture pictureType =-> Just PictureData+ { pictureMimeType = "image/png"+ , pictureDescription = ""+ , pictureWidth = fromIntegral (imageWidth image)+ , pictureHeight = fromIntegral (imageHeight image)+ , pictureDepth = 24+ , pictureColors = 0 -- non-indexed+ , pictureData = BL.toStrict (encodePng image)+ }
+ LICENSE.md view
@@ -0,0 +1,28 @@+Copyright © 2017 Mark Karpov++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 Mark Karpov nor the names of 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 “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 HOLDERS 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.
+ README.md view
@@ -0,0 +1,17 @@+# FLAC Picture++[](http://opensource.org/licenses/BSD-3-Clause)+[](https://hackage.haskell.org/package/flac-picture)+[](http://stackage.org/nightly/package/flac-picture)+[](http://stackage.org/lts/package/flac-picture)+[](https://travis-ci.org/mrkkrp/flac-picture)+[](https://coveralls.io/github/mrkkrp/flac-picture?branch=master)++I bet you always wanted to write a picture into FLAC metadata blocks. I'll+tell you what, with **Haskell** you can do it.++## License++Copyright © 2017 Mark Karpov++Distributed under BSD 3 clause license.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ audio-samples/sample.flac view
binary file changed (absent → 11459 bytes)
+ flac-picture.cabal view
@@ -0,0 +1,91 @@+--+-- Cabal configuration for ‘flac-picture’ package.+--+-- Copyright © 2017 Mark Karpov <markkarpov@openmailbox.org>+--+-- 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 Mark Karpov nor the names of 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 “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 HOLDERS 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.++name: flac-picture+version: 0.1.0+cabal-version: >= 1.10+license: BSD3+license-file: LICENSE.md+author: Mark Karpov <markkarpov@openmailbox.org>+maintainer: Mark Karpov <markkarpov@openmailbox.org>+homepage: https://github.com/mrkkrp/flac-picture+bug-reports: https://github.com/mrkkrp/flac-picture/issues+category: Codec, Audio, Image+synopsis: Support for writing picture to FLAC metadata blocks with JuicyPixels+build-type: Simple+description: Support for writing picture to FLAC metadata blocks with JuicyPixels.+extra-doc-files: CHANGELOG.md+ , README.md+data-files: audio-samples/*.flac+ , picture-samples/*.jpeg+ , picture-samples/*.png++source-repository head+ type: git+ location: https://github.com/mrkkrp/flac-picture.git++flag dev+ description: Turn on development settings.+ manual: True+ default: False++library+ build-depends: JuicyPixels >= 3.2.6.5 && < 4.0+ , base >= 4.7 && < 5.0+ , bytestring >= 0.2 && < 0.11+ , flac >= 0.1 && < 0.2+ exposed-modules: Codec.Audio.FLAC.Metadata.Picture+ if flag(dev)+ ghc-options: -Wall -Werror+ else+ ghc-options: -O2 -Wall+ default-language: Haskell2010++test-suite tests+ main-is: Spec.hs+ other-modules: Codec.Audio.FLAC.Metadata.PictureSpec+ hs-source-dirs: tests+ type: exitcode-stdio-1.0+ build-depends: JuicyPixels >= 3.2.6.5 && < 4.0+ , base >= 4.7 && < 5.0+ , bytestring >= 0.2 && < 0.11+ , data-default-class+ , directory >= 1.2.2 && < 1.3+ , flac >= 0.1 && < 0.2+ , flac-picture >= 0.1.0+ , hspec >= 2.0 && < 3.0+ , temporary >= 1.1 && < 1.3+ if flag(dev)+ ghc-options: -Wall -Werror+ else+ ghc-options: -O2 -Wall+ default-language: Haskell2010
+ picture-samples/lenna.jpeg view
binary file changed (absent → 7614 bytes)
+ picture-samples/lenna.png view
binary file changed (absent → 7514 bytes)
+ tests/Codec/Audio/FLAC/Metadata/PictureSpec.hs view
@@ -0,0 +1,105 @@+--+-- Tests for the ‘flac-picture’ package.+--+-- Copyright © 2017 Mark Karpov <markkarpov@openmailbox.org>+--+-- 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 Mark Karpov nor the names of 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 “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 HOLDERS 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.++{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Codec.Audio.FLAC.Metadata.PictureSpec+ ( spec )+where++import Codec.Audio.FLAC.Metadata+import Codec.Audio.FLAC.Metadata.Picture+import Codec.Picture+import Control.Monad+import Data.Default.Class+import Data.Function (on)+import System.Directory+import System.IO+import System.IO.Temp (withSystemTempFile)+import Test.Hspec+import qualified Data.ByteString.Lazy as BL++spec :: Spec+spec = around withSandbox $ do+ describe "writeJpegPicture/retrieveImage" . forM_ [minBound..maxBound] $ \ptype ->+ it ("writes JPEG picture and reads it back: " ++ show ptype) $ \path -> do+ Right (ImageYCbCr8 pic) <- readJpeg "picture-samples/lenna.jpeg"+ runFlacMeta def path (writeJpegPicture ptype 127 pic)+ let Right (ImageYCbCr8 pic'') = (decodeJpeg . BL.toStrict)+ (encodeJpegAtQuality 100 pic)+ Just PictureData {..} <- runFlacMeta def path (retrieve $ Picture ptype)+ pictureMimeType `shouldBe` "image/jpeg"+ pictureDescription `shouldBe` ""+ pictureWidth `shouldBe` fromIntegral (imageWidth pic)+ pictureHeight `shouldBe` fromIntegral (imageHeight pic)+ pictureDepth `shouldBe` 24+ pictureColors `shouldBe` 0+ Right (ImageYCbCr8 pic') <- runFlacMeta def path (retrieveImage ptype)+ pic' `imageShouldBe` pic''+ describe "writePngPicture/retrieveImage" . forM_ [minBound..maxBound] $ \ptype ->+ it ("writes PNG picture and reads it back: " ++ show ptype) $ \path -> do+ Right (ImageRGB8 pic) <- readPng "picture-samples/lenna.png"+ runFlacMeta def path (writePngPicture ptype pic)+ Just PictureData {..} <- runFlacMeta def path (retrieve $ Picture ptype)+ pictureMimeType `shouldBe` "image/png"+ pictureDescription `shouldBe` ""+ pictureWidth `shouldBe` fromIntegral (imageWidth pic)+ pictureHeight `shouldBe` fromIntegral (imageHeight pic)+ pictureDepth `shouldBe` 24+ pictureColors `shouldBe` 0+ Right (ImageRGB8 pic') <- runFlacMeta def path (retrieveImage ptype)+ pic' `imageShouldBe` pic++----------------------------------------------------------------------------+-- Helpers++-- | Make a temporary copy of @audio-samples/sample.flac@ file and provide+-- the path to the file. Automatically remove the file when the test+-- finishes.++withSandbox :: ActionWith FilePath -> IO ()+withSandbox action = withSystemTempFile "sample.flac" $ \path h -> do+ hClose h+ copyFile "audio-samples/sample.flac" path+ action path++imageShouldBe+ :: (Pixel a, Show (PixelBaseComponent a), Eq (PixelBaseComponent a))+ => Image a+ -> Image a+ -> Expectation+imageShouldBe img0 img1 = do+ (shouldBe `on` imageWidth) img0 img1+ (shouldBe `on` imageHeight) img0 img1+ (shouldBe `on` imageData) img0 img1
+ tests/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}