diff options
Diffstat (limited to 'compiler/src/FileProcessors.hs')
-rw-r--r-- | compiler/src/FileProcessors.hs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/compiler/src/FileProcessors.hs b/compiler/src/FileProcessors.hs new file mode 100644 index 0000000..5c4e1c8 --- /dev/null +++ b/compiler/src/FileProcessors.hs | |||
@@ -0,0 +1,128 @@ | |||
1 | -- ldgallery - A static generator which turns a collection of tagged | ||
2 | -- pictures into a searchable web gallery. | ||
3 | -- | ||
4 | -- Copyright (C) 2019-2020 Pacien TRAN-GIRARD | ||
5 | -- | ||
6 | -- This program is free software: you can redistribute it and/or modify | ||
7 | -- it under the terms of the GNU Affero General Public License as | ||
8 | -- published by the Free Software Foundation, either version 3 of the | ||
9 | -- License, or (at your option) any later version. | ||
10 | -- | ||
11 | -- This program is distributed in the hope that it will be useful, | ||
12 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | -- GNU Affero General Public License for more details. | ||
15 | -- | ||
16 | -- You should have received a copy of the GNU Affero General Public License | ||
17 | -- along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
18 | |||
19 | module FileProcessors | ||
20 | ( FileProcessor | ||
21 | , transformThenDescribe | ||
22 | , copyResource | ||
23 | , noopProcessor | ||
24 | , FileTransformer | ||
25 | , copyFileProcessor | ||
26 | , resizePictureUpTo | ||
27 | , resourceAt | ||
28 | , getImageResolution | ||
29 | , FileDescriber | ||
30 | , getResProps | ||
31 | , getPictureProps | ||
32 | , getThumbnailProps | ||
33 | ) where | ||
34 | |||
35 | |||
36 | import Control.Exception (Exception, throwIO) | ||
37 | import System.Process (readProcess, callProcess) | ||
38 | import Text.Read (readMaybe) | ||
39 | |||
40 | import System.Directory (getModificationTime) | ||
41 | import qualified System.Directory | ||
42 | |||
43 | import Config (Resolution(..)) | ||
44 | import Resource (Resource(..), GalleryItemProps(..), Thumbnail(..)) | ||
45 | import Files | ||
46 | |||
47 | |||
48 | data ProcessingException = ProcessingException FilePath String deriving Show | ||
49 | instance Exception ProcessingException | ||
50 | |||
51 | type FileProcessor a = | ||
52 | Path -- ^ Item path | ||
53 | -> Path -- ^ Target resource path | ||
54 | -> FilePath -- ^ Filesystem input path | ||
55 | -> FilePath -- ^ Filesystem output path | ||
56 | -> IO a | ||
57 | |||
58 | transformThenDescribe :: FileTransformer -> FileDescriber a -> FileProcessor a | ||
59 | transformThenDescribe transformer describer _itemPath resPath fsInPath fsOutPath = | ||
60 | transformer fsInPath fsOutPath >> describer resPath fsOutPath | ||
61 | |||
62 | copyResource :: (Resource -> a) -> FileProcessor a | ||
63 | copyResource resPropConstructor = | ||
64 | transformThenDescribe copyFileProcessor (getResProps resPropConstructor) | ||
65 | |||
66 | noopProcessor :: FileProcessor (Maybe a) | ||
67 | noopProcessor _ _ _ _ = return Nothing | ||
68 | |||
69 | |||
70 | type FileTransformer = | ||
71 | FileName -- ^ Input path | ||
72 | -> FileName -- ^ Output path | ||
73 | -> IO () | ||
74 | |||
75 | copyFileProcessor :: FileTransformer | ||
76 | copyFileProcessor inputPath outputPath = | ||
77 | putStrLn ("Copying:\t" ++ outputPath) | ||
78 | >> ensureParentDir (flip System.Directory.copyFile) outputPath inputPath | ||
79 | |||
80 | resizePictureUpTo :: Resolution -> FileTransformer | ||
81 | resizePictureUpTo maxResolution inputPath outputPath = | ||
82 | putStrLn ("Generating:\t" ++ outputPath) | ||
83 | >> ensureParentDir (flip resize) outputPath inputPath | ||
84 | where | ||
85 | maxSize :: Resolution -> String | ||
86 | maxSize Resolution{width, height} = show width ++ "x" ++ show height ++ ">" | ||
87 | |||
88 | resize :: FileName -> FileName -> IO () | ||
89 | resize input output = callProcess "magick" | ||
90 | [ input | ||
91 | , "-auto-orient" | ||
92 | , "-resize", maxSize maxResolution | ||
93 | , output ] | ||
94 | |||
95 | |||
96 | type FileDescriber a = | ||
97 | Path -- ^ Target resource path | ||
98 | -> FilePath -- ^ Filesystem path | ||
99 | -> IO a | ||
100 | |||
101 | getImageResolution :: FilePath -> IO Resolution | ||
102 | getImageResolution fsPath = | ||
103 | readProcess "magick" ["identify", "-format", "%w %h", firstFrame] [] | ||
104 | >>= parseResolution . break (== ' ') | ||
105 | where | ||
106 | firstFrame :: FilePath | ||
107 | firstFrame = fsPath ++ "[0]" | ||
108 | |||
109 | parseResolution :: (String, String) -> IO Resolution | ||
110 | parseResolution (widthString, heightString) = | ||
111 | case (readMaybe widthString, readMaybe heightString) of | ||
112 | (Just w, Just h) -> return $ Resolution w h | ||
113 | _ -> throwIO $ ProcessingException fsPath "Unable to read image resolution." | ||
114 | |||
115 | resourceAt :: FileDescriber Resource | ||
116 | resourceAt resPath fsPath = Resource resPath <$> getModificationTime fsPath | ||
117 | |||
118 | getResProps :: (Resource -> a) -> FileDescriber a | ||
119 | getResProps resPropsConstructor resPath fsPath = | ||
120 | resPropsConstructor <$> resourceAt resPath fsPath | ||
121 | |||
122 | getPictureProps :: FileDescriber GalleryItemProps | ||
123 | getPictureProps resPath fsPath = | ||
124 | Picture <$> resourceAt resPath fsPath <*> getImageResolution fsPath | ||
125 | |||
126 | getThumbnailProps :: FileDescriber (Maybe Thumbnail) | ||
127 | getThumbnailProps resPath fsPath = | ||
128 | Just <$> (Thumbnail <$> resourceAt resPath fsPath <*> getImageResolution fsPath) | ||