Skip to content

Commit

Permalink
Lua: add new module pandoc.image
Browse files Browse the repository at this point in the history
The module provides basic querying functions for image properties.
  • Loading branch information
tarleb authored and jgm committed Apr 16, 2024
1 parent 9a09c89 commit 5f937ea
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 0 deletions.
61 changes: 61 additions & 0 deletions doc/lua-filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions pandoc-lua-engine/pandoc-lua-engine.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions pandoc-lua-engine/src/Text/Pandoc/Lua/Init.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions pandoc-lua-engine/src/Text/Pandoc/Lua/Marshal/ImageSize.hs
Original file line number Diff line number Diff line change
@@ -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 <albert+pandoc@tarleb.com>
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)
]
98 changes: 98 additions & 0 deletions pandoc-lua-engine/src/Text/Pandoc/Lua/Module/Image.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{-# LANGUAGE OverloadedStrings #-}
{-|
Module : Text.Pandoc.Lua.Module.Image
Copyright : © 2024 Albert Krewinkel
License : MIT
Maintainer : Albert Krewinkel <albert+pandoc@tarleb.com>
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*."
]
2 changes: 2 additions & 0 deletions pandoc-lua-engine/test/Tests/Lua/Module.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
68 changes: 68 additions & 0 deletions pandoc-lua-engine/test/lua/module/pandoc-image.lua
Original file line number Diff line number Diff line change
@@ -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),
},
}

0 comments on commit 5f937ea

Please sign in to comment.