diff options
| author | Albert Krewinkel <[email protected]> | 2024-01-17 12:19:20 +0100 |
|---|---|---|
| committer | John MacFarlane <[email protected]> | 2024-04-16 10:23:08 -0700 |
| commit | 5f937eae617d72f5f01e24f5a72bafc5b04fde15 (patch) | |
| tree | 99a21e079e428b93561e12a45ecc6a0961cc5f09 | |
| parent | 9a09c89636e78edaed52276a2b3e00fb7368631b (diff) | |
Lua: add new module `pandoc.image`
The module provides basic querying functions for image properties.
| -rw-r--r-- | doc/lua-filters.md | 61 | ||||
| -rw-r--r-- | pandoc-lua-engine/pandoc-lua-engine.cabal | 2 | ||||
| -rw-r--r-- | pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs | 2 | ||||
| -rw-r--r-- | pandoc-lua-engine/src/Text/Pandoc/Lua/Marshal/ImageSize.hs | 31 | ||||
| -rw-r--r-- | pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Image.hs | 98 | ||||
| -rw-r--r-- | pandoc-lua-engine/test/Tests/Lua/Module.hs | 2 | ||||
| -rw-r--r-- | pandoc-lua-engine/test/lua/module/pandoc-image.lua | 68 |
7 files changed, 264 insertions, 0 deletions
diff --git a/doc/lua-filters.md b/doc/lua-filters.md index e1504ff13..3872e1cba 100644 --- a/doc/lua-filters.md +++ b/doc/lua-filters.md @@ -4607,6 +4607,67 @@ Returns: <!-- END: AUTOGENERATED CONTENT --> +<!-- BEGIN: AUTOGENERATED CONTENT for module pandoc.image --> + +# Module pandoc.image + +Basic image querying functions. + +## Functions {#pandoc.image-functions} + +### size {#pandoc.image.size} + +`size (image[, opts])` + +Returns a table containing the size and resolution of an image; +throws an error if the given string is not an image, or if the +size of the image cannot be determined. + +The resulting table has four entires: *width*, *height*, +*dpi_horz*, and *dpi_vert*. + +The `opts` parameter, when given, should be either a WriterOptions +object such as `PANDOC_WRITER_OPTIONS`, or a table with a `dpi` +entry. It affects the calculation for vector image formats such as +SVG. + +Parameters: + +`image` +: image data (string) + +`opts` +: writer options ([WriterOptions]\|table) + +Returns: + +- image size information or error message (table) + +*Since: 3.1.13* + +### format {#pandoc.image.format} + +`format (image)` + +Returns the format of an image as a lowercase string. + +Formats recognized by pandoc include *png*, *gif*, *tiff*, *jpeg*, +*pdf*, *svg*, *eps*, and *emf*. + +Parameters: + +`image` +: binary image data (string) + +Returns: + +- image format, or nil if the format cannot be determined + (string\|nil) + +*Since: 3.1.13* + +<!-- END: AUTOGENERATED CONTENT --> + <!-- BEGIN: AUTOGENERATED CONTENT for module pandoc.json --> # Module pandoc.json diff --git a/pandoc-lua-engine/pandoc-lua-engine.cabal b/pandoc-lua-engine/pandoc-lua-engine.cabal index 3e101a4f2..27cfb75cc 100644 --- a/pandoc-lua-engine/pandoc-lua-engine.cabal +++ b/pandoc-lua-engine/pandoc-lua-engine.cabal @@ -74,6 +74,7 @@ library , Text.Pandoc.Lua.Marshal.CommonState , Text.Pandoc.Lua.Marshal.Context , Text.Pandoc.Lua.Marshal.Format + , Text.Pandoc.Lua.Marshal.ImageSize , Text.Pandoc.Lua.Marshal.PandocError , Text.Pandoc.Lua.Marshal.ReaderOptions , Text.Pandoc.Lua.Marshal.Reference @@ -82,6 +83,7 @@ library , Text.Pandoc.Lua.Marshal.WriterOptions , Text.Pandoc.Lua.Module.CLI , Text.Pandoc.Lua.Module.Format + , Text.Pandoc.Lua.Module.Image , Text.Pandoc.Lua.Module.JSON , Text.Pandoc.Lua.Module.MediaBag , Text.Pandoc.Lua.Module.Pandoc diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs index 2900fea27..0ea04b635 100644 --- a/pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs @@ -41,6 +41,7 @@ import qualified HsLua.Module.Path as Module.Path import qualified HsLua.Module.Zip as Module.Zip import qualified Text.Pandoc.Lua.Module.CLI as Pandoc.CLI import qualified Text.Pandoc.Lua.Module.Format as Pandoc.Format +import qualified Text.Pandoc.Lua.Module.Image as Pandoc.Image import qualified Text.Pandoc.Lua.Module.JSON as Pandoc.JSON import qualified Text.Pandoc.Lua.Module.MediaBag as Pandoc.MediaBag import qualified Text.Pandoc.Lua.Module.Pandoc as Module.Pandoc @@ -91,6 +92,7 @@ loadedModules :: [Module PandocError] loadedModules = [ Pandoc.CLI.documentedModule , Pandoc.Format.documentedModule + , Pandoc.Image.documentedModule , Pandoc.JSON.documentedModule , Pandoc.MediaBag.documentedModule , Pandoc.Scaffolding.documentedModule diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Marshal/ImageSize.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Marshal/ImageSize.hs new file mode 100644 index 000000000..e56b5cd25 --- /dev/null +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Marshal/ImageSize.hs @@ -0,0 +1,31 @@ +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{- | + Module : Text.Pandoc.Lua.Marshal.ImageSize + Copyright : © 2024 Albert Krewinkel + License : GPL-2.0-or-later + Maintainer : Albert Krewinkel <[email protected]> + +Marshaling image properties. +-} +module Text.Pandoc.Lua.Marshal.ImageSize + ( pushImageType + , pushImageSize + ) where + +import Data.Char (toLower) +import HsLua +import Text.Pandoc.ImageSize + +-- | Pushes an 'ImageType' as a string value. +pushImageType :: LuaError e => Pusher e ImageType +pushImageType = pushString . map toLower . show + +-- | Pushes a dimensional value. +pushImageSize :: LuaError e => Pusher e ImageSize +pushImageSize = pushAsTable + [ ("width", pushIntegral . pxX) + , ("height", pushIntegral . pxY) + , ("dpi_horz", pushIntegral . dpiX) + , ("dpi_vert", pushIntegral . dpiY) + ] diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Image.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Image.hs new file mode 100644 index 000000000..3b2465ccc --- /dev/null +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Image.hs @@ -0,0 +1,98 @@ +{-# LANGUAGE OverloadedStrings #-} +{-| +Module : Text.Pandoc.Lua.Module.Image +Copyright : © 2024 Albert Krewinkel +License : MIT +Maintainer : Albert Krewinkel <[email protected]> + +Lua module for basic image operations. +-} +module Text.Pandoc.Lua.Module.Image ( + -- * Module + documentedModule + + -- ** Functions + , size + , format + ) +where + +import Prelude hiding (null) +import Data.Default (Default (def)) +import Data.Maybe (fromMaybe) +import Data.Version (makeVersion) +import HsLua.Core +import HsLua.Marshalling +import HsLua.Packaging +import Text.Pandoc.Error (PandocError) +import Text.Pandoc.ImageSize (imageType, imageSize) +import Text.Pandoc.Lua.PandocLua () +import Text.Pandoc.Lua.Marshal.ImageSize (pushImageType, pushImageSize) +import Text.Pandoc.Lua.Marshal.WriterOptions (peekWriterOptions) + +import qualified Data.Text as T + +-- | The @pandoc.image@ module specification. +documentedModule :: Module PandocError +documentedModule = Module + { moduleName = "pandoc.image" + , moduleDescription = "Basic image querying functions." + , moduleFields = fields + , moduleFunctions = functions + , moduleOperations = [] + , moduleTypeInitializers = [] + } + +-- +-- Fields +-- + +-- | Exported fields. +fields :: LuaError e => [Field e] +fields = [] + +-- +-- Functions +-- + +functions :: [DocumentedFunction PandocError] +functions = + [ size `since` makeVersion [3, 1, 13] + , format `since` makeVersion [3, 1, 13] + ] + +-- | Find the size of an image. +size :: DocumentedFunction PandocError +size = defun "size" + ### liftPure2 (\img mwriterOpts -> imageSize (fromMaybe def mwriterOpts) img) + <#> parameter peekByteString "string" "image" "image data" + <#> opt (parameter peekWriterOptions "WriterOptions|table" "opts" + "writer options") + =#> functionResult (either (failLua . T.unpack) pushImageSize) "table" + "image size information or error message" + #? T.unlines + [ "Returns a table containing the size and resolution of an image;" + , "throws an error if the given string is not an image, or if the size" + , "of the image cannot be determined." + , "" + , "The resulting table has four entires: *width*, *height*, *dpi\\_horz*," + , "and *dpi\\_vert*." + , "" + , "The `opts` parameter, when given, should be either a WriterOptions" + , "object such as `PANDOC_WRITER_OPTIONS`, or a table with a `dpi` entry." + , "It affects the calculation for vector image formats such as SVG." + ] + +-- | Returns the format of an image. +format :: LuaError e => DocumentedFunction e +format = defun "format" + ### liftPure imageType + <#> parameter peekByteString "string" "image" "binary image data" + =#> functionResult (maybe pushnil pushImageType) "string|nil" + "image format, or nil if the format cannot be determined" + #? T.unlines + [ "Returns the format of an image as a lowercase string." + , "" + , "Formats recognized by pandoc include *png*, *gif*, *tiff*, *jpeg*," + , "*pdf*, *svg*, *eps*, and *emf*." + ] diff --git a/pandoc-lua-engine/test/Tests/Lua/Module.hs b/pandoc-lua-engine/test/Tests/Lua/Module.hs index e3556f2cd..ff85f1292 100644 --- a/pandoc-lua-engine/test/Tests/Lua/Module.hs +++ b/pandoc-lua-engine/test/Tests/Lua/Module.hs @@ -25,6 +25,8 @@ tests = ("lua" </> "module" </> "pandoc-list.lua") , testPandocLua "pandoc.format" ("lua" </> "module" </> "pandoc-format.lua") + , testPandocLua "pandoc.image" + ("lua" </> "module" </> "pandoc-image.lua") , testPandocLua "pandoc.json" ("lua" </> "module" </> "pandoc-json.lua") , testPandocLua "pandoc.mediabag" diff --git a/pandoc-lua-engine/test/lua/module/pandoc-image.lua b/pandoc-lua-engine/test/lua/module/pandoc-image.lua new file mode 100644 index 000000000..72f261449 --- /dev/null +++ b/pandoc-lua-engine/test/lua/module/pandoc-image.lua @@ -0,0 +1,68 @@ +-- +-- Tests for the system module +-- +local image = require 'pandoc.image' +local tasty = require 'tasty' + +local group = tasty.test_group +local test = tasty.test_case +local assert = tasty.assert + +local svg_image = [==[<?xml version="1.0"?> +<svg xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + height="70" width="70" + viewBox="-35 -35 70 70"> + <title>test</title> + <!-- document shape --> + <polygon points="-10,-31.53 -10,-3.25 0,0 10,-3.25 10,-23.53 2,-31.53" /> +</svg> +]==] + +return { + -- Check existence of static fields + group 'static fields' { + }, + + group 'size' { + test('returns a table', function () + local imgsize = { + width = 70, + height = 70, + dpi_horz = 96, + dpi_vert = 96, + } + assert.are_same(image.size(svg_image), imgsize) + end), + test('fails on faulty eps', function () + assert.error_matches( + function () image.size('%!PS EPSF') end, + 'could not determine EPS size' + ) + end), + test('fails if input is not an image', function () + assert.error_matches( + function () image.size('not an image') end, + 'could not determine image type' + ) + end), + test('respects the dpi setting', function () + local imgsize = { + width = 70, + height = 70, + dpi_horz = 300, + dpi_vert = 300, + } + assert.are_same(image.size(svg_image, {dpi=300}), imgsize) + end), + }, + + group 'format' { + test('SVG', function () + assert.are_equal(image.format(svg_image), 'svg') + end), + test('returns nil if input is not an image', function () + assert.is_nil(image.format('not an image')) + end), + }, +} |
