module ImageStore (Buffer,getBufferSize, ImageVersion, vWidth, vHeight, vPath, Size, saveImage, deleteImage) where import Buffer import Config import ImageInfo import qualified Graphics.GD as GD import Data.Char import Control.Monad import Data.Ratio import System.Directory type Size = (Int,Int) type ImageVersion = (Size, FilePath) vWidth :: ImageVersion -> Int vWidth = fst . fst vHeight :: ImageVersion -> Int vHeight = snd . fst vPath :: ImageVersion -> FilePath vPath = snd saveImage :: ImageID -- ^ image id (must be unique) -> Buffer -- ^ image data -> String -- ^ name -> [Size] -- ^ image sizes to save, in addition to the full image. -> IO (ImageVersion,[ImageVersion]) -- ^ full image size, full image path, -- resized image sizes and paths. saveImage imgid buf name sizes = do let file = imageFileName imgid name origPath = imgdir ++ "/" ++ file createDirectoryIfMissing True imgdir writeBufferFile origPath buf img <- withBufferPtr buf (\ (p,l) -> GD.loadJpegData l p) size <- GD.imageSize img resized <- mapM (saveResized img file size) sizes return ((size, origPath), resized) imageFileName :: ImageID -> String -> String imageFileName imgid name = showImageID imgid ++ "-" ++ name' where name' = filter okChar name okChar c = isAlpha c || isDigit c || c `elem` "!\"#$%&'()*+,-.@[]^_`:;<=>?{|}~" saveResized :: GD.Image -> String -> Size -> Size -> IO ImageVersion saveResized img file sz maxSz = do let dir = sizedir maxSz path = dir ++ "/" ++ file newSz@(w,h) = calcSize sz maxSz createDirectoryIfMissing True dir img' <- GD.resizeImage img w h GD.saveJpeg img' path (-1) return (newSz, path) sizedir :: Size -> FilePath sizedir (w,h) = imgdir ++ "/" ++ show w ++ "x" ++ show h -- | Find the best size to resize to, given the desired size. calcSize :: Size -- ^ current size -> Size -- ^ wanted size -> Size -- ^ largest size smaller than wanted size -- such that the aspect ratio is preserved. calcSize (inW,inH) (outW,outH) | inAspect > outAspect = (outW, round (fromIntegral outW / inAspect)) | inAspect < outAspect = (round (fromIntegral outH * inAspect), outH) | otherwise = (outW, outH) where inAspect = inW % inH outAspect = outW % outH -- | Delete the given image. deleteImage :: ImageInfo -> IO () deleteImage info = do removeFile (fullFile info) removeFile (thumbFile info) removeFile (viewFile info)