includesvg incompatible with setkeys{Gin}
ChrisJefferson opened this issue · 16 comments
The following latex file looks weirdly corrupted. The problem is the use of Gin
I think?
\documentclass{article}
\usepackage{svg}
\usepackage{graphicx}
\setkeys{Gin}{height=3cm,keepaspectratio}
\begin{document}
\includesvg{bubbleup.svg}
\end{document}
The problem is the use of
Gin
I think?
Exactly. This is not part of the interface. I could implement it once I will find some time but this won't happen in the near future. And honestly, I am not keen to do this as this potentially increases the need for maintenance without any real benefit as there is a working interface.
Using global settings for graphics dimensions seems odd to me anyway. Nevertheless, you could achieve this by using \svgsetup
accordingly (although for the particular image, height=3cm
is way to small):
\documentclass{article}
\usepackage{svg}
\begin{document}
\svgsetup{height=3cm,keepaspectratio}
\includesvg{bubbleup}
\end{document}
Hi, thank you for your quick reply.
If you don't mind, I'll explain the background of this problem a bit more.
I am using pandoc
, a common program for transforming between various file formats. I was getting some broken output.
Looking at pandoc, it uses the following latex template ( https://github.com/jgm/pandoc/blob/main/data/templates/default.latex ) , which contains the following (it's quite long, and the $ are handled before the code is given to latex). This template is used for all files generated, so I guess this Gin
business is to handle all types of images.
$if(graphics)$
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
$endif$
$if(svg)$
\usepackage{svg}
$endif$
I realise it is not your job to fix this, but is there a suggested fix I can give to pandoc?
I realise it is not your job to fix this, but is there a suggested fix I can give to pandoc?
I already saw the linked issue and had a brief look. That's why showed the way you could achieve the desired behavior with \svgsetup
. So, regarding to the given snippet of the pandoc setup, it would just be \svgsetup{width=\maxwidth,height=\maxheight,keepaspectratio}
.
An additional note: the conditional $if(svg)$
should probably be nested into the previous one as package svg
loads graphicx
anyway and with the current setup, the latter could be loaded without the desired setup.
Thanks!
Unfortunately, that doesn't seem to work (everything just gets rendered on top of each other). I guess this might be because the \maxwidth
and \maxheight
are themselves full of references to \Gin
? This is far beyond my latex ability!
The pandoc setup should IMHO look like this
$if(graphics)$
\usepackage{graphicx}
\makeatletter
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\makeatother
% Scale images if necessary, so that they will not overflow the page
% margins by default, and it is still possible to overwrite the defaults
% using explicit options in \includegraphics[width, height, ...]{}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
% Set default figure placement to htbp
\makeatletter
\def\fps@figure{htbp}
\makeatother
$if(svg)$
\usepackage{svg}
\svgsetup{width=\maxwidth,height=\maxheight,keepaspectratio}
$endif$
$endif$
whereas it needs to be ensured, that $if(graphics)$
is set in case $if(svg)$
is required or the very first conditional would be something like $if(graphics) or (svg)$
(not quite sure if this is valid for pandoc). This change would have to be applied to the pandoc setup.
The problem here is, that pandoc relies on the internals of package graphicx
/graphics
by using \Gin@nat@width
and \Gin@nat@height
which are set, when \includegraphics
is invoked. But package svg
needs no know the desired size of the file to be included beforehand, which is why this approach fails as well.
So, there is currently no short-term workaround I can think of besides just explicitly specifying the desired size of the image via \includesvg[width=..., height=...]{<svg-file>}
.
Thank you very much for looking into this, we will see how pandoc wants to clean things up!
it needs to be ensured, that
$if(graphics)$
is set in case$if(svg)$
is required
That is already ensured.
Question: why can't the svg package use the SVG size information encoded in the SVG's attributes
<svg width="597.89pt" height="1075pt" version="1.1" viewBox="0 0 597.89 1075.2" xmlns="http://www.w3.org/2000/svg">
when no [width=_,height=_]
option is provided?
Package svg
is nothing but a wrapper for the (latex) export functionality provided by Inkscape. It does not touch the SVG file itself.
Just to be clear, the native image size is used by default. It only fails with pandoc because of the provided settings via \setkeys{Gin}
OK, I see. The Gin
business is supposed to scale images that extend beyond textwidth to textwidth, but somehow with the svg it scales it down to tiny.
I don't think removing the Gin
stuff is a good option for us; it was added for a reason. Is there any other way to ensure that images that would overflow textwidth are resized appropriately?
OK, I see. The
Gin
business is supposed to scale images that extend beyond textwidth to textwidth, but somehow with the svg it scales it down to tiny.
That's because \Gin@nat@width
and \Gin@nat@height
are set during the invocation of \includegraphics
internally but package svg
needs to know the desired output size beforehand. This relates to the format of *.pdf_tex
files exported via Inkscape. In particular, those files are using lines like \includegraphics[width=\unitlength,...]{...}
and in order to provide capability for scaling the resulting output, package svg
has to adapt \unitlength
accordingly.
I don't think removing the
Gin
stuff is a good option for us; it was added for a reason. Is there any other way to ensure that images that would overflow textwidth are resized appropriately?
Well, a similar but different approach would be, not to modify the default settings of package graphicx
but to scale the output provided by both \includegraphics
and \includesvg
in a generic way. The sample provided below defines a command \pandocbounded{...}
which can be used as a generic wrapper for any output content which should not extend both \textheight
and \linewidth
by:
- Store the desired output in a box
- Determine horizontal and vertical scaling factors regarding
\textheight
and\linewidth
by evaluating the box size - Choose the smaller factor
- Scale the content of the box if factor is smaller than 1, otherwise use the content as it is
\documentclass{article}
\usepackage{graphicx}
\usepackage{svg}
\makeatletter
\newsavebox\pandoc@box
\newcommand*\pandocbounded[1]{%
\sbox\pandoc@box{#1}%
% scaling factors for width and height
\Gscale@div\@tempa\textheight{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}%
\Gscale@div\@tempb\linewidth{\wd\pandoc@box}%
% select the smaller of both
\ifdim\@tempb\p@<\@tempa\p@
\let\@tempa\@tempb
\fi
% scaling accordingly (\@tempa < 1)
\ifdim\@tempa\p@<\p@
\scalebox{\@tempa}{\usebox\pandoc@box}%
% scaling not needed, use as it is
\else
\usebox{\pandoc@box}%
\fi
}
\makeatother
\begin{document}
\pandocbounded{\includegraphics{<graphic-file>}}
\pandocbounded{\includesvg{<svg-file>}}
\end{document}
I am not familiar how pandoc is actually generating LaTeX source files. But \pandocbounded{...}
should obviously only be used, if no setting regarding the graphic size is given. But this is something, you are probably aware of.
Don't hesitate to ask for more, if needed ;)
Thank you for this suggestion! Pandoc tries to emit fairly vanilla looking LaTeX, since it can also be used in "fragment" mode (where it doesn't produce a preamble). And I'd also prefer to avoid a change that breaks existing templates. So, I'm exploring an approach that uses the approach you sketched but redefines \includegraphics
and \includesvg
so they do this automatically. It is working, so far.
One question: why should \pandocbounded
not be used if a setting for the graphic size is given? It seems to work fine in that case, in my tests. (Obviously, it prevents you from setting the size to greater than the text width...but I think that's okay.)
All that said, this approach is quite ugly compared to the Gin
approach (in the sense that it involves a big chunk of code in the preamble). So, another option is for us just to tell people that if they run into this sort of problem they should specify an explicit size for the SVG (which is probably a good idea anyway).
Pandoc tries to emit fairly vanilla looking LaTeX, since it can also be used in "fragment" mode (where it doesn't produce a preamble). And I'd also prefer to avoid a change that breaks existing templates. So, I'm exploring an approach that uses the approach you sketched but redefines
\includegraphics
and\includesvg
so they do this automatically. It is working, so far.
IMHO, if you do patch \includegraphics
and \includesvg
(which is tedious, error-prone and can potentially lead to high maintenance costs) and the behavior changes whether pandoc is in charge, that's no vanilla LaTeX anymore but rather obfuscated code. With your current setup via \setkeys{Gin}{...}
the output of \includegraphics[width=5cm,height=2cm]{example-image-A}
in "fragment" mode is already different as keepaspectration=false
is the default for graphicx
.
This said, I am quite familiar with the burden of improving user interface or default settings but not to break anything out there.
One question: why should
\pandocbounded
not be used if a setting for the graphic size is given? It seems to work fine in that case, in my tests. (Obviously, it prevents you from setting the size to greater than the text width...but I think that's okay.)
That's exactly the use case I am talking about. If a user requests a width larger than 100%, for whatever reason, why should pandoc overrule this. In my eyes, scaling down images occasionally rather than giving a hint that user action is recommended, actually should have been opt-in in the first place. But once something is public...
All that said, this approach is quite ugly compared to the
Gin
approach (in the sense that it involves a big chunk of code in the preamble).
Well, if you measure the ugliness of code directly proportional to lines of code written then this is more beautiful:
\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
in comparison to this:
\newsavebox\pandoc@box
\newcommand*\pandocbounded[1]{%
\sbox\pandoc@box{#1}%
\Gscale@div\@tempa{\textheight}{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}%
\Gscale@div\@tempb{\linewidth}{\wd\pandoc@box}%
\ifdim\@tempb\p@<\@tempa\p@\let\@tempa\@tempb\fi% select the smaller of both
\ifdim\@tempa\p@<\p@\scalebox{\@tempa}{\usebox\pandoc@box}\else\usebox{\pandoc@box}\fi
}
But considering your initial approach relies on both internals as well as implementation details and is obviously not working in any case, this should maybe get a second view. It actually only works because \Gin@nat@width
and \Gin@nat@height
are calculated by graphicx
before parameters are evaluated. But if this is changed or those two internals are removed, your setup will break. As the development of l3backend-graphics
is ongoing (hopefully with native support of SVG file at some point) it is not unlikely, that package graphicx
is deprecated and/or \includegraphics
is re-implemented.
So, another option is for us just to tell people that if they run into this sort of problem they should specify an explicit size for the SVG (which is probably a good idea anyway).
IMHO, the best solution would be to use the approach I came up with, extended by an user message to specify an image size, if down-scaling was necessary, ensuring, this does not happen unnoticed. Regarding the "fragment" mode, if dropping \pandocbounded
is not that easy for pandoc in the first place, maybe just reprocessing the generated output and retaining just the content of \pandocbounded
's argument could work?
If this would be tedious (e.g. because dealing nested braces in regex expressions is annoying), you could make your live easier with some TeX magic like:
\newcommand*\pandocbounded{}
\def\pandocbounded#1\pandocboundedstop{%
...
}
and then use it like this
\pandocbounded\includegraphics{<graphic-file>}\pandocboundedstop
\pandocbounded
\includesvg{<svg-file>}
\pandocboundedstop
which should be very easy to remove in a second stage in "fragmet" mode.
Hopefully, you don't get me wrong, I am really amazed about the capabilities of pandoc and really appreciate your efforts. I learned LaTeX the hard way multiple times and I just want to prevent you from making the same mistakes again I already made.
Thanks for these comments. I think you're probably right that this is the best approach, but breaking changes like this are always messy. I will ponder it.
I don't want "fragment" mode to give different output than "standalone" mode. But maybe it's not so bad if the fragment mode output includes \pandocbounded
. We already use a command defined in the preamble to modify spacing in "tight" lists, and this would be similar to that.
Fixed with jgm/pandoc#9666