diff --git a/patacrep/data/templates/songs/chordpro/chordpro/content_image b/patacrep/data/templates/songs/chordpro/chordpro/content_image index 4f9bf06c..7398eec3 100644 --- a/patacrep/data/templates/songs/chordpro/chordpro/content_image +++ b/patacrep/data/templates/songs/chordpro/chordpro/content_image @@ -1 +1 @@ -{image: (( content.argument|search_image ))} +{image: "(( content.filename|search_image ))" ((content.size|render_size))} diff --git a/patacrep/data/templates/songs/chordpro/latex/content_image b/patacrep/data/templates/songs/chordpro/latex/content_image index a567730d..be75cec6 100644 --- a/patacrep/data/templates/songs/chordpro/latex/content_image +++ b/patacrep/data/templates/songs/chordpro/latex/content_image @@ -1,6 +1,6 @@ (* block image *) -(* set image = content.argument|search_image|path2posix *) +(* set image = content.filename|search_image|path2posix *) (* if image *) -\image{(( image ))} +\image[(( content.size|render_size ))]{(( image ))} (*- endif *) (*- endblock *) diff --git a/patacrep/data/templates/styles/patacrep.sty b/patacrep/data/templates/styles/patacrep.sty index 8b88af75..4413b996 100644 --- a/patacrep/data/templates/styles/patacrep.sty +++ b/patacrep/data/templates/styles/patacrep.sty @@ -6,6 +6,7 @@ \NeedsTeXFormat{LaTeX2e}[1994/06/01] \ProvidesPackage{patacrep}[2014/06/17 Patacrep Package, version 1] +\RequirePackage[space]{grffile} \RequirePackage{graphicx,xcolor} % \RequirePackage{epstopdf} % \RequirePackage{fancybox} diff --git a/patacrep/songs/chordpro/__init__.py b/patacrep/songs/chordpro/__init__.py index 6f1ca655..8464131f 100644 --- a/patacrep/songs/chordpro/__init__.py +++ b/patacrep/songs/chordpro/__init__.py @@ -182,6 +182,7 @@ class Chordpro2LatexSong(ChordproSong): parent = super()._filters() parent.update({ 'lang2babel': self.lang2babel, + 'render_size': self._render_size, }) return parent @@ -203,6 +204,13 @@ class Chordpro2LatexSong(ChordproSong): self.errors.append(new_error) return error.babel + @staticmethod + def _render_size(size): + items = [] + for name, value, unit in size: + items.append(name + "=" + value + unit) + return ", ".join(items) + class Chordpro2ChordproSong(ChordproSong): """Render chordpro song to chordpro code""" @@ -219,10 +227,25 @@ class Chordpro2ChordproSong(ChordproSong): '\\': '\\\\', } + def _filters(self): + parent = super()._filters() + parent.update({ + 'render_size': self._render_size, + }) + return parent + def search_file(self, filename, extensions=None, *, datadirs=None): # pylint: disable=unused-variable return filename + @staticmethod + def _render_size(size): + items = [] + for name, value, unit in size: + items.append(name + "=" + value + unit) + return " ".join(items) + + SONG_RENDERERS = { "tsg": { 'csg': Chordpro2LatexSong, diff --git a/patacrep/songs/chordpro/ast.py b/patacrep/songs/chordpro/ast.py index 37dbae28..6f764e34 100644 --- a/patacrep/songs/chordpro/ast.py +++ b/patacrep/songs/chordpro/ast.py @@ -405,6 +405,22 @@ class Define(Directive): def __str__(self): return None +class Image(Directive): + """An image + + .. attribute:: filename + The filename of the image. + .. attribute:: size + An iterable of tuples ``(type, float, unit)``. + """ + + def __init__(self, filename, size=None): + self.filename = filename + if size is None: + size = [] + self.size = size + super().__init__("image", None) + class Tab(AST): """Tablature""" diff --git a/patacrep/songs/chordpro/syntax.py b/patacrep/songs/chordpro/syntax.py index 9a7b9feb..a1e3f6e6 100644 --- a/patacrep/songs/chordpro/syntax.py +++ b/patacrep/songs/chordpro/syntax.py @@ -2,6 +2,7 @@ import logging import re +import shlex import ply.yacc as yacc @@ -124,10 +125,67 @@ class ChordproParser(Parser): fingers=fingers, ) + def _iter_raw_image_size_arguments(self, arguments, *, lineno): + for item in arguments: + prefix, _, suffix = item.partition("=") + if prefix in ['width', 'height']: + match = re.compile( + r"^(?P(\d*\.\d+|\d+))(?Pcm|em|pt)$", + re.VERBOSE, + ).match(suffix) + if match is not None: + yield (prefix, match.groupdict()['value'], match.groupdict()['unit']) + continue + elif prefix in ['scale']: + match = re.compile( + r"^(?P(\d*\.\d+|\d+))$", + re.VERBOSE, + ).match(suffix) + if match is not None: + yield (prefix, match.groupdict()['value'], "") + continue + else: + self.error( + line=lineno, + message="Image: Unknown argument name '{}'.".format(prefix), + ) + continue + self.error( + line=lineno, + message="Image: Unsupported {} value: '{}'.".format(prefix, suffix), + ) + + def _iter_image_size_arguments(self, argument, *, lineno): + arguments = set() + length_names = frozenset(["width", "height"]) + for name, value, unit in self._iter_raw_image_size_arguments(argument, lineno=lineno): + if name in arguments: + self.error( + line=lineno, + message="Image: Ignoring repeated argument: {}.".format(name), + ) + continue + if ( + name == "scale" and not length_names.isdisjoint(arguments) + ) or ( + name in length_names and "scale" in arguments + ): + self.error( + line=lineno, + message=( + "Image: Ignoring '{}' argument: Cannot mix scale and " + "width or height argument." + ).format(name), + ) + continue + arguments.add(name) + yield name, value, unit + def p_directive(self, symbols): """directive : LBRACE KEYWORD directive_next RBRACE | LBRACE SPACE KEYWORD directive_next RBRACE """ + # pylint: disable=too-many-branches if len(symbols) == 5: keyword = symbols[2] argument = symbols[3] @@ -171,7 +229,21 @@ class ChordproParser(Parser): symbols[0] = ast.Error() return self._directives.append(define) - + elif keyword == "image": + splitted = shlex.split(argument) + if len(splitted) < 1: + self.error( + line=symbols.lexer.lineno, + message="Missing filename for image directive", + ) + symbols[0] = ast.Error() + else: + symbols[0] = ast.Image( + splitted[0], + list( + self._iter_image_size_arguments(splitted[1:], lineno=symbols.lexer.lineno) + ), + ) else: directive = ast.Directive(keyword, argument) if directive.inline: diff --git a/test/test_book/datadir.tex.control b/test/test_book/datadir.tex.control index 687a6096..bdc8a210 100644 --- a/test/test_book/datadir.tex.control +++ b/test/test_book/datadir.tex.control @@ -111,7 +111,7 @@ Chordpro}[ \lilypond{scores/datadir.ly} -\image{img/datadir.png} +\image[]{img/datadir.png} \endsong @@ -138,7 +138,7 @@ Chordpro}[ \lilypond{scores/datadir2.ly} -\image{img/datadir2.png} +\image[]{img/datadir2.png} \endsong @@ -165,7 +165,7 @@ Chordpro}[ \lilypond{@TEST_FOLDER@/datadir_datadir/songs/./relative.ly} -\image{@TEST_FOLDER@/datadir_datadir/songs/./relative.png} +\image[]{@TEST_FOLDER@/datadir_datadir/songs/./relative.png} \endsong @@ -192,7 +192,7 @@ Chordpro}[ \lilypond{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.ly} -\image{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.png} +\image[]{@TEST_FOLDER@/datadir_datadir/songs/./subdir/subdir.png} \endsong diff --git a/test/test_book/syntax.tex.control b/test/test_book/syntax.tex.control index af7acb06..719dfc2f 100644 --- a/test/test_book/syntax.tex.control +++ b/test/test_book/syntax.tex.control @@ -2,8 +2,6 @@ - - %% Automatically generated document. %% You may edit this file but all changes will be overwritten. %% If you want to change this document, have a look at @@ -91,6 +89,69 @@ guitar, \addcontentsline{toc}{section}{\songlistname} \begin{songs}{titleidx,authidx} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% songs/./images.csg + +\selectlanguage{english} + +\beginsong{}[ + by={ + }, +] + + +\image[]{img/image.png} +\image[]{img/image with spaces.png} + + + +\image[scale=2]{img/image.png} +\image[scale=.20]{img/image with spaces.png} +\image[scale=1.2]{img/image.png} + + + +\image[width=2cm]{img/image.png} +\image[height=2cm]{img/image with spaces.png} +\image[width=2cm, height=1cm]{img/image.png} + + + +\image[width=2em]{img/image.png} +\image[height=2em]{img/image with spaces.png} +\image[width=2em, height=1em]{img/image.png} + + + +\image[width=50pt]{img/image.png} +\image[height=50pt]{img/image with spaces.png} +\image[width=50pt, height=100pt]{img/image.png} + + + +\image[width=2.5cm]{img/image.png} +\image[height=2.5cm]{img/image with spaces.png} +\image[width=2.5cm, height=1.5cm]{img/image.png} + + + +\image[width=3cm, height=10pt]{img/image.png} +\image[width=10pt, height=3cm]{img/image with spaces.png} + + + +\image[]{img/image.png} +\image[]{img/image.png} +\image[]{img/image with spaces.png} +\image[]{img/image with spaces.png} +\image[]{img/image.png} +\image[width=2cm]{img/image.png} +\image[width=2cm]{img/image.png} +\image[width=2cm]{img/image.png} + + +\endsong + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% songs/./musicnote.csg @@ -117,4 +178,4 @@ guitar, -\end{document} \ No newline at end of file +\end{document} diff --git a/test/test_book/syntax_datadir/img/image with spaces.png b/test/test_book/syntax_datadir/img/image with spaces.png new file mode 100644 index 00000000..f088bf46 Binary files /dev/null and b/test/test_book/syntax_datadir/img/image with spaces.png differ diff --git a/test/test_book/syntax_datadir/img/image.png b/test/test_book/syntax_datadir/img/image.png new file mode 100644 index 00000000..f088bf46 Binary files /dev/null and b/test/test_book/syntax_datadir/img/image.png differ diff --git a/test/test_book/syntax_datadir/songs/images.csg b/test/test_book/syntax_datadir/songs/images.csg new file mode 100644 index 00000000..49d843a2 --- /dev/null +++ b/test/test_book/syntax_datadir/songs/images.csg @@ -0,0 +1,35 @@ +{image: image.png} +{image: "image with spaces.png"} + +{image: image.png scale=2 } +{image: "image with spaces.png" scale=.20} +{image: image.png scale=1.2} + +{image: image.png width=2cm} +{image: "image with spaces.png" height=2cm} +{image: image.png width=2cm height=1cm} + +{image: image.png width=2em} +{image: "image with spaces.png" height=2em} +{image: image.png width=2em height=1em} + +{image: image.png width=50pt} +{image: "image with spaces.png" height=50pt} +{image: image.png width=50pt height=100pt} + +{image: image.png width=2.5cm} +{image: "image with spaces.png" height=2.5cm} +{image: image.png width=2.5cm height=1.5cm} + +{image: image.png width=3cm height=10pt} +{image: "image with spaces.png" width=10pt height=3cm} + +{image: image.png width= height=} +{image: image.png error=foo} +{image: "image with spaces.png" not_a_size} +{image: "image with spaces.png" too many arguments} +{image: image.png width=2ex height=3km} +{image: image.png width=2cm width=3cm} +{image: image.png width=2cm scale=3cm} +{image: image.png width=2cm scale=3} +{image: } diff --git a/test/test_song/image with spaces.png b/test/test_song/image with spaces.png new file mode 100644 index 00000000..e69de29b diff --git a/test/test_song/image.csg b/test/test_song/image.csg new file mode 100644 index 00000000..9f698456 --- /dev/null +++ b/test/test_song/image.csg @@ -0,0 +1,44 @@ +{lang: en} + +{image: "image.png" } +{image: "image with spaces.png" } + + +{image: "image.png" scale=2} +{image: "image with spaces.png" scale=.20} +{image: "image.png" scale=1.2} + + +{image: "image.png" width=2cm} +{image: "image with spaces.png" height=2cm} +{image: "image.png" width=2cm height=1cm} + + +{image: "image.png" width=2em} +{image: "image with spaces.png" height=2em} +{image: "image.png" width=2em height=1em} + + +{image: "image.png" width=50pt} +{image: "image with spaces.png" height=50pt} +{image: "image.png" width=50pt height=100pt} + + +{image: "image.png" width=2.5cm} +{image: "image with spaces.png" height=2.5cm} +{image: "image.png" width=2.5cm height=1.5cm} + + +{image: "image.png" width=3cm height=10pt} +{image: "image with spaces.png" width=10pt height=3cm} + + +{image: "image.png" } +{image: "image.png" } +{image: "image with spaces.png" } +{image: "image with spaces.png" } +{image: "image.png" } +{image: "image.png" width=2cm} +{image: "image.png" width=2cm} +{image: "image.png" width=2cm} + diff --git a/test/test_song/image.csg.source b/test/test_song/image.csg.source new file mode 100644 index 00000000..49d843a2 --- /dev/null +++ b/test/test_song/image.csg.source @@ -0,0 +1,35 @@ +{image: image.png} +{image: "image with spaces.png"} + +{image: image.png scale=2 } +{image: "image with spaces.png" scale=.20} +{image: image.png scale=1.2} + +{image: image.png width=2cm} +{image: "image with spaces.png" height=2cm} +{image: image.png width=2cm height=1cm} + +{image: image.png width=2em} +{image: "image with spaces.png" height=2em} +{image: image.png width=2em height=1em} + +{image: image.png width=50pt} +{image: "image with spaces.png" height=50pt} +{image: image.png width=50pt height=100pt} + +{image: image.png width=2.5cm} +{image: "image with spaces.png" height=2.5cm} +{image: image.png width=2.5cm height=1.5cm} + +{image: image.png width=3cm height=10pt} +{image: "image with spaces.png" width=10pt height=3cm} + +{image: image.png width= height=} +{image: image.png error=foo} +{image: "image with spaces.png" not_a_size} +{image: "image with spaces.png" too many arguments} +{image: image.png width=2ex height=3km} +{image: image.png width=2cm width=3cm} +{image: image.png width=2cm scale=3cm} +{image: image.png width=2cm scale=3} +{image: } diff --git a/test/test_song/image.png b/test/test_song/image.png new file mode 100644 index 00000000..e69de29b diff --git a/test/test_song/image.tsg b/test/test_song/image.tsg new file mode 100644 index 00000000..1ec6a98d --- /dev/null +++ b/test/test_song/image.tsg @@ -0,0 +1,59 @@ +\selectlanguage{english} + +\beginsong{}[ + by={ + }, +] + + +\image[]{img/image.png} +\image[]{img/image with spaces.png} + + + +\image[scale=2]{img/image.png} +\image[scale=.20]{img/image with spaces.png} +\image[scale=1.2]{img/image.png} + + + +\image[width=2cm]{img/image.png} +\image[height=2cm]{img/image with spaces.png} +\image[width=2cm, height=1cm]{img/image.png} + + + +\image[width=2em]{img/image.png} +\image[height=2em]{img/image with spaces.png} +\image[width=2em, height=1em]{img/image.png} + + + +\image[width=50pt]{img/image.png} +\image[height=50pt]{img/image with spaces.png} +\image[width=50pt, height=100pt]{img/image.png} + + + +\image[width=2.5cm]{img/image.png} +\image[height=2.5cm]{img/image with spaces.png} +\image[width=2.5cm, height=1.5cm]{img/image.png} + + + +\image[width=3cm, height=10pt]{img/image.png} +\image[width=10pt, height=3cm]{img/image with spaces.png} + + + +\image[]{img/image.png} +\image[]{img/image.png} +\image[]{img/image with spaces.png} +\image[]{img/image with spaces.png} +\image[]{img/image.png} +\image[width=2cm]{img/image.png} +\image[width=2cm]{img/image.png} +\image[width=2cm]{img/image.png} + + +\endsong \ No newline at end of file diff --git a/test/test_song/metadata.csg b/test/test_song/metadata.csg index 322a591b..825b8ece 100644 --- a/test/test_song/metadata.csg +++ b/test/test_song/metadata.csg @@ -16,7 +16,7 @@ {comment: Comment} {guitar_comment: GuitarComment} {partition: metadata_lilypond} -{image: metadata_image} +{image: "metadata_image" } Foo diff --git a/test/test_song/metadata.tsg b/test/test_song/metadata.tsg index 52582de4..09c768bf 100644 --- a/test/test_song/metadata.tsg +++ b/test/test_song/metadata.tsg @@ -20,7 +20,7 @@ Subtitle5}[ \textnote{Comment} \musicnote{GuitarComment} \lilypond{scores/metadata_lilypond} -\image{img/metadata_image} +\image[]{img/metadata_image}