module Codec.Picture.Png.Streaming
(
decodePNG
, decodePNGComplete
, decodePNGFile
, decodeHeader
, PNGDecodeError(..)
, DecodedPNG
, HeaderData(..)
, ChunkType
, BitDepth
, ColourType
, CompressionMethod
, FilterMethod
, FilterType
, InterlaceMethod
, isColourTypeSupported
, isCompressionMethodSupported
, isFilterMethodSupported
, isInterlaceMethodSupported
)
where
import Codec.Picture.Png.Streaming.Core
import Codec.Picture.Png.Streaming.Header
import Codec.Picture.Png.Streaming.Info
import Codec.Picture.Png.Streaming.MainData
import Codec.Picture.Png.Streaming.Util
import Control.Monad (unless)
import Control.Monad.Catch (MonadThrow (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans (MonadTrans (..))
import Control.Monad.Trans.Resource (MonadResource)
import Data.ByteString.Streaming (ByteString)
import qualified Data.ByteString.Streaming as Q
import Streaming.Prelude (Of (..))
type DecodedPNG m r = Of HeaderData (ByteString m r)
decodePNG :: (MonadThrow m, MonadIO m) => ByteString m r -> m (DecodedPNG m (ByteString m r))
decodePNG input =
do (hd :> rest) <- takeHeaderData (decodePNGChunks input)
unless (isImageTypeSupported hd) (throwM UnsupportedImageType)
return (hd :> decodeImageData hd rest)
decodeHeader :: (MonadThrow m) => ByteString m r -> m (Of HeaderData (ByteString m r))
decodeHeader input =
do PNGChunk{..} <-
either (const $ throwM UnexpectedEOF) return
=<< decodeChunk input
unless (chunkType == ctIHDR) (throwM (UnexpectedChunk chunkType))
tryDecodeHeader chunkData
decodePNGComplete :: (MonadThrow m, MonadIO m) => ByteString m r -> m (DecodedPNG m r)
decodePNGComplete input =
do (hd :> rest) <- decodePNG input
let rest' = lift . expectNull ExpectedEOF =<< rest
return (hd :> rest')
decodePNGFile :: (MonadResource m) => FilePath -> m (DecodedPNG m ())
decodePNGFile = decodePNGComplete . Q.readFile
isImageTypeSupported :: HeaderData -> Bool
isImageTypeSupported HeaderData{..} =
isColourTypeSupported hdColourType &&
isCompressionMethodSupported hdCompressionMethod &&
isFilterMethodSupported hdFilterMethod &&
isInterlaceMethodSupported hdInterlaceMethod
isColourTypeSupported :: ColourType -> Bool
isColourTypeSupported = (`elem` [0, 2, 4, 6])
isCompressionMethodSupported :: CompressionMethod -> Bool
isCompressionMethodSupported = (== 0)
isFilterMethodSupported :: FilterMethod -> Bool
isFilterMethodSupported = (== 0)
isInterlaceMethodSupported :: InterlaceMethod -> Bool
isInterlaceMethodSupported = (== 0)