Add image rendering alongside automatic mimetype detection

This commit is contained in:
Marko Andjelic 2026-01-26 02:59:11 +00:00
commit 396a9cdb16
3 changed files with 34 additions and 4 deletions

View file

@ -19,12 +19,13 @@ import qualified Data.Text.Encoding as TE
import Control.Monad.Reader (ReaderT, MonadReader(ask), liftIO) import Control.Monad.Reader (ReaderT, MonadReader(ask), liftIO)
import Control.Monad.Except (runExceptT) import Control.Monad.Except (runExceptT)
import Text.HTML.TagSoup (parseTags, Tag(..)) import Text.HTML.TagSoup (parseTags, Tag(..))
import System.FilePath (takeDirectory, (</>), normalise) import System.FilePath (takeDirectory, (</>), normalise, takeExtension)
import Data.List (find) import Data.List (find)
import Codec.Epub.Parse (getManifest , getSpine) import Codec.Epub.Parse (getManifest , getSpine)
import qualified Codec.Epub.Data.Manifest as DM import qualified Codec.Epub.Data.Manifest as DM
import qualified Codec.Epub.Data.Spine as DS import qualified Codec.Epub.Data.Spine as DS
import qualified Data.ByteString.Base64 as B64
type EpubAction a = ReaderT EpubEnv IO a type EpubAction a = ReaderT EpubEnv IO a
@ -85,4 +86,32 @@ getChapter filename = do
let full = normalise (baseDir env </> filename) let full = normalise (baseDir env </> filename)
case findEntryByPath full (archive env) of case findEntryByPath full (archive env) of
Nothing -> pure [] Nothing -> pure []
Just e -> pure $ parseTags . TE.decodeUtf8 . B.toStrict $ fromEntry e Just e -> do
pure $ embedImages (archive env) (baseDir env) (parseTags . TE.decodeUtf8 . B.toStrict $ fromEntry e) -- The base64 img
getMimeType :: FilePath -> T.Text
getMimeType path = T.pack $ "image/" ++ normalizeExt (drop 1 $ takeExtension path)
where
normalizeExt :: String -> String
normalizeExt ext
| ext == "jpg" = "jpeg"
| otherwise = ext
embedImages :: Archive -> FilePath -> [Tag T.Text] -> [Tag T.Text]
embedImages arch bdir = map processTag
where
processTag (TagOpen "img" attrs) = TagOpen "img" (map replaceSrc attrs)
processTag other = other
replaceSrc (name, value)
| name == "src" = ("src", findImage value)
| otherwise = (name, value)
findImage path =
let fullPath = normalise (bdir </> T.unpack path)
in case findEntryByPath fullPath arch of
Nothing -> path
Just entry ->
let rawData = B.toStrict $ fromEntry entry
b64 = TE.decodeUtf8 $ B64.encode rawData
in "data:" <> getMimeType fullPath <> ";base64," <> b64

View file

@ -15,7 +15,7 @@ runWindow htmlContent = do
_ <- Gtk.on app #activate $ do _ <- Gtk.on app #activate $ do
window <- Gtk.applicationWindowNew app window <- Gtk.applicationWindowNew app
Gtk.windowSetTitle window (Just "Svitak Reader (GTK 4)") Gtk.windowSetTitle window (Just "Svitak")
Gtk.windowSetDefaultSize window 800 600 Gtk.windowSetDefaultSize window 800 600

View file

@ -73,7 +73,8 @@ executable svitak
gi-gtk == 4.0.*, gi-gtk == 4.0.*,
gi-webkit == 6.0.*, gi-webkit == 6.0.*,
gi-gio, gi-gio,
haskell-gi-base haskell-gi-base,
base64-bytestring
hs-source-dirs: app hs-source-dirs: app
default-language: Haskell2010 default-language: Haskell2010