mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #5992 from jfbu/latex_safe_graphics
LaTeX: safer image inclusion
This commit is contained in:
commit
ed86ada661
3
CHANGES
3
CHANGES
@ -62,6 +62,9 @@ Incompatible changes
|
|||||||
* websupport: unbundled from sphinx core. Please use sphinxcontrib-websupport
|
* websupport: unbundled from sphinx core. Please use sphinxcontrib-websupport
|
||||||
* C++, the visibility of base classes is now always rendered as present in the
|
* C++, the visibility of base classes is now always rendered as present in the
|
||||||
input. That is, ``private`` is now shown, where it was ellided before.
|
input. That is, ``private`` is now shown, where it was ellided before.
|
||||||
|
* LaTeX: graphics inclusion of oversized images rescales to not exceed
|
||||||
|
the text width and height, even if width and/or height option were used.
|
||||||
|
(refs: #5956)
|
||||||
|
|
||||||
Deprecated
|
Deprecated
|
||||||
----------
|
----------
|
||||||
|
@ -707,53 +707,79 @@
|
|||||||
|
|
||||||
%% GRAPHICS
|
%% GRAPHICS
|
||||||
%
|
%
|
||||||
% \sphinxincludegraphics defined to resize images larger than the line width,
|
% \sphinxincludegraphics resizes images larger than the TeX \linewidth (which
|
||||||
% except if height or width option present.
|
% is adjusted in indented environments), or taller than a certain maximal
|
||||||
|
% height (usually \textheight and this is reduced in the environments which use
|
||||||
|
% framed.sty to avoid infinite loop if image too tall).
|
||||||
%
|
%
|
||||||
% If scale is present, rescale before fitting to line width. (since 1.5)
|
% In case height or width options are present the rescaling is done
|
||||||
\newbox\spx@image@box
|
% (since 2.0), in a way keeping the width:height ratio either native from
|
||||||
\newcommand*{\sphinxincludegraphics}[2][]{%
|
% image or from the width and height options if both were present.
|
||||||
\in@{height}{#1}\ifin@\else\in@{width}{#1}\fi
|
%
|
||||||
\ifin@ % height or width present
|
\newdimen\spx@image@maxheight
|
||||||
\includegraphics[#1]{#2}%
|
\AtBeginDocument{\spx@image@maxheight\textheight}
|
||||||
\else % no height nor width (but #1 may be "scale=...")
|
|
||||||
|
% box scratch register
|
||||||
|
\newdimen\spx@image@box
|
||||||
|
\newcommand*{\sphinxsafeincludegraphics}[2][]{%
|
||||||
|
% #1 contains possibly width=, height=, but no scale= since 1.8.4
|
||||||
\setbox\spx@image@box\hbox{\includegraphics[#1,draft]{#2}}%
|
\setbox\spx@image@box\hbox{\includegraphics[#1,draft]{#2}}%
|
||||||
|
\in@false % use some handy boolean flag
|
||||||
\ifdim \wd\spx@image@box>\linewidth
|
\ifdim \wd\spx@image@box>\linewidth
|
||||||
\setbox\spx@image@box\box\voidb@x % clear memory
|
\in@true % flag to remember to adjust options and set box dimensions
|
||||||
\includegraphics[#1,width=\linewidth]{#2}%
|
% compute height which results from rescaling width to \linewidth
|
||||||
|
% and keep current aspect ratio. multiply-divide in \numexpr uses
|
||||||
|
% temporarily doubled precision, hence no overflow. (of course we
|
||||||
|
% assume \ht is not a few sp's below \maxdimen...(about 16384pt).
|
||||||
|
\edef\spx@image@rescaledheight % with sp units
|
||||||
|
{\the\numexpr\ht\spx@image@box
|
||||||
|
*\linewidth/\wd\spx@image@box sp}%
|
||||||
|
\ifdim\spx@image@rescaledheight>\spx@image@maxheight
|
||||||
|
% the rescaled height will be too big, so it is height which decides
|
||||||
|
% the rescaling factor
|
||||||
|
\def\spx@image@requiredheight{\spx@image@maxheight}% dimen register
|
||||||
|
\edef\spx@image@requiredwidth % with sp units
|
||||||
|
{\the\numexpr\wd\spx@image@box
|
||||||
|
*\spx@image@maxheight/\ht\spx@image@box sp}%
|
||||||
|
% TODO: decide if this commented-out block could be needed due to
|
||||||
|
% rounding in numexpr operations going up
|
||||||
|
% \ifdim\spx@image@requiredwidth>\linewidth
|
||||||
|
% \def\spx@image@requiredwidth{\linewidth}% dimen register
|
||||||
|
% \fi
|
||||||
|
\else
|
||||||
|
\def\spx@image@requiredwidth{\linewidth}% dimen register
|
||||||
|
\let\spx@image@requiredheight\spx@image@rescaledheight% sp units
|
||||||
|
\fi
|
||||||
\else
|
\else
|
||||||
|
% width is ok, let's check height
|
||||||
|
\ifdim\ht\spx@image@box>\spx@image@maxheight
|
||||||
|
\in@true
|
||||||
|
\edef\spx@image@requiredwidth % with sp units
|
||||||
|
{\the\numexpr\wd\spx@image@box
|
||||||
|
*\spx@image@maxheight/\ht\spx@image@box sp}%
|
||||||
|
\def\spx@image@requiredheight{\spx@image@maxheight}% dimen register
|
||||||
|
\fi
|
||||||
|
\fi % end of check of width and height
|
||||||
|
\ifin@
|
||||||
|
\setbox\spx@image@box
|
||||||
|
\hbox{\includegraphics
|
||||||
|
[%#1,% contained only width and/or height and overruled anyhow
|
||||||
|
width=\spx@image@requiredwidth,height=\spx@image@requiredheight]%
|
||||||
|
{#2}}%
|
||||||
|
% \includegraphics does not set box dimensions to the exactly
|
||||||
|
% requested ones, see https://github.com/latex3/latex2e/issues/112
|
||||||
|
\wd\spx@image@box\spx@image@requiredwidth
|
||||||
|
\ht\spx@image@box\spx@image@requiredheight
|
||||||
|
\leavevmode\box\spx@image@box
|
||||||
|
\else
|
||||||
|
% here we do not modify the options, no need to adjust width and height
|
||||||
|
% on output, they will be computed exactly as with "draft" option
|
||||||
\setbox\spx@image@box\box\voidb@x % clear memory
|
\setbox\spx@image@box\box\voidb@x % clear memory
|
||||||
\includegraphics[#1]{#2}%
|
\includegraphics[#1]{#2}%
|
||||||
\fi
|
\fi
|
||||||
\fi
|
|
||||||
}
|
|
||||||
% \sphinxsafeincludegraphics resizes images larger than the line width,
|
|
||||||
% or taller than about the text height (whether or not height/width options
|
|
||||||
% were used). This is requested to avoid a crash with \MakeFramed as used by
|
|
||||||
% sphinxShadowBox (topic/contents) and sphinxheavybox (admonitions), and also
|
|
||||||
% by sphinxVerbatim (but a priori no image inclusion there).
|
|
||||||
\newdimen\spx@image@maxheight
|
|
||||||
% default maximal setting will get reduced by sphinxShadowBox/sphinxheavybox
|
|
||||||
\AtBeginDocument{\spx@image@maxheight\textheight}
|
|
||||||
\newcommand*{\sphinxsafeincludegraphics}[2][]{%
|
|
||||||
\gdef\spx@includegraphics@options{#1}%
|
|
||||||
\setbox\spx@image@box\hbox{\includegraphics[#1,draft]{#2}}%
|
|
||||||
\in@false
|
|
||||||
\ifdim \wd\spx@image@box>\linewidth
|
|
||||||
\g@addto@macro\spx@includegraphics@options{,width=\linewidth}%
|
|
||||||
\in@true
|
|
||||||
\fi
|
|
||||||
% no rotation, no need to worry about depth
|
|
||||||
\ifdim \ht\spx@image@box>\spx@image@maxheight
|
|
||||||
\g@addto@macro\spx@includegraphics@options{,height=\spx@image@maxheight}%
|
|
||||||
\in@true
|
|
||||||
\fi
|
|
||||||
\ifin@
|
|
||||||
\g@addto@macro\spx@includegraphics@options{,keepaspectratio}%
|
|
||||||
\fi
|
|
||||||
\setbox\spx@image@box\box\voidb@x % clear memory
|
|
||||||
\expandafter\includegraphics\expandafter[\spx@includegraphics@options]{#2}%
|
|
||||||
}%
|
}%
|
||||||
|
% Use the "safe" one by default (2.0)
|
||||||
|
\def\sphinxincludegraphics{\sphinxsafeincludegraphics}
|
||||||
|
|
||||||
|
|
||||||
%% FIGURE IN TABLE
|
%% FIGURE IN TABLE
|
||||||
@ -1374,7 +1400,6 @@
|
|||||||
+2\sphinxshadowsep
|
+2\sphinxshadowsep
|
||||||
+\sphinxshadowsize
|
+\sphinxshadowsize
|
||||||
+\baselineskip\relax
|
+\baselineskip\relax
|
||||||
\let\sphinxincludegraphics\sphinxsafeincludegraphics
|
|
||||||
% configure framed.sty not to add extra vertical spacing
|
% configure framed.sty not to add extra vertical spacing
|
||||||
\ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}%
|
\ltx@ifundefined{OuterFrameSep}{}{\OuterFrameSep\z@skip}%
|
||||||
% the \trivlist will add the vertical spacing on top and bottom which is
|
% the \trivlist will add the vertical spacing on top and bottom which is
|
||||||
@ -1461,7 +1486,6 @@
|
|||||||
-\dimexpr2\FrameRule
|
-\dimexpr2\FrameRule
|
||||||
+2\FrameSep
|
+2\FrameSep
|
||||||
+\baselineskip\relax % will happen again if nested, needed indeed!
|
+\baselineskip\relax % will happen again if nested, needed indeed!
|
||||||
\let\sphinxincludegraphics\sphinxsafeincludegraphics
|
|
||||||
% configure framed.sty's parameters to obtain same vertical spacing
|
% configure framed.sty's parameters to obtain same vertical spacing
|
||||||
% as for "light" boxes. We need for this to manually insert parskip glue and
|
% as for "light" boxes. We need for this to manually insert parskip glue and
|
||||||
% revert a skip done by framed before the frame.
|
% revert a skip done by framed before the frame.
|
||||||
|
49
tests/roots/test-latex-includegraphics/conf.py
Normal file
49
tests/roots/test-latex-includegraphics/conf.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
master_doc = 'index'
|
||||||
|
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
'preamble': r'''
|
||||||
|
\makeatletter
|
||||||
|
\def\dividetwolengths#1#2{\the\dimexpr
|
||||||
|
\numexpr65536*\dimexpr#1\relax/\dimexpr#2\relax sp}%
|
||||||
|
\newwrite\out
|
||||||
|
\immediate\openout\out=\jobname-dimensions.txt
|
||||||
|
\def\toout{\immediate\write\out}
|
||||||
|
\def\getWfromoptions #1width=#2,#3\relax{\def\WidthFromOption{#2}}%
|
||||||
|
\def\getHfromoptions #1height=#2,#3\relax{\def\HeightFromOption{#2}}%
|
||||||
|
\def\tempincludegraphics[#1]#2{%
|
||||||
|
\sphinxsafeincludegraphics[#1]{#2}%
|
||||||
|
\edef\obtainedratio
|
||||||
|
{\dividetwolengths\spx@image@requiredheight\spx@image@requiredwidth}%
|
||||||
|
\getWfromoptions#1,width=,\relax
|
||||||
|
\getHfromoptions#1,height=,\relax
|
||||||
|
\def\ratiocheck{}%
|
||||||
|
\ifx\WidthFromOption\empty\else
|
||||||
|
\ifx\HeightFromOption\empty\else
|
||||||
|
\edef\askedforratio{\dividetwolengths\HeightFromOption\WidthFromOption}%
|
||||||
|
\edef\ratiocheck{\dividetwolengths\obtainedratio\askedforratio}%
|
||||||
|
\fi\fi
|
||||||
|
\toout{original options = #1^^J%
|
||||||
|
width = \the\dimexpr\spx@image@requiredwidth,
|
||||||
|
linewidth = \the\linewidth^^J%
|
||||||
|
height = \the\dimexpr\spx@image@requiredheight,
|
||||||
|
maxheight = \the\spx@image@maxheight^^J%
|
||||||
|
obtained H/W = \obtainedratio^^J%
|
||||||
|
\ifx\ratiocheck\empty
|
||||||
|
\else
|
||||||
|
asked for H/W = \askedforratio^^J%
|
||||||
|
ratio of ratios = \ratiocheck^^J%
|
||||||
|
\fi
|
||||||
|
}%
|
||||||
|
\ifx\ratiocheck\empty
|
||||||
|
\else
|
||||||
|
\ifpdfabsdim\dimexpr\ratiocheck-1pt\relax > 0.01pt
|
||||||
|
\ASPECTRATIOERROR
|
||||||
|
\fi
|
||||||
|
\fi
|
||||||
|
}
|
||||||
|
\def\sphinxincludegraphics#1#{\tempincludegraphics#1}
|
||||||
|
\makeatother
|
||||||
|
''',
|
||||||
|
}
|
BIN
tests/roots/test-latex-includegraphics/img.png
Normal file
BIN
tests/roots/test-latex-includegraphics/img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
37
tests/roots/test-latex-includegraphics/index.rst
Normal file
37
tests/roots/test-latex-includegraphics/index.rst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
====================
|
||||||
|
Test image inclusion
|
||||||
|
====================
|
||||||
|
|
||||||
|
Tests with both width and height
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. an image with big dimensions, ratio H/W = 1/5
|
||||||
|
.. image:: img.png
|
||||||
|
:height: 200
|
||||||
|
:width: 1000
|
||||||
|
|
||||||
|
.. topic:: Oversized images
|
||||||
|
|
||||||
|
.. an image with big dimensions, ratio H/W = 5/1
|
||||||
|
.. image:: img.png
|
||||||
|
:height: 1000
|
||||||
|
:width: 200
|
||||||
|
|
||||||
|
.. height too big even if width reduced to linewidth, ratio H/W = 3/1
|
||||||
|
.. image:: img.png
|
||||||
|
:width: 1000
|
||||||
|
:height: 3000
|
||||||
|
|
||||||
|
Tests with only width or height
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
.. topic:: Oversized images
|
||||||
|
|
||||||
|
.. tall image which does not fit in textheight even if width rescaled
|
||||||
|
.. image:: tall.png
|
||||||
|
:width: 1000
|
||||||
|
|
||||||
|
.. wide image which does not fit in linewidth even after height diminished
|
||||||
|
.. image:: sphinx.png
|
||||||
|
:height: 1000
|
||||||
|
|
BIN
tests/roots/test-latex-includegraphics/sphinx.png
Normal file
BIN
tests/roots/test-latex-includegraphics/sphinx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
tests/roots/test-latex-includegraphics/tall.png
Normal file
BIN
tests/roots/test-latex-includegraphics/tall.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
@ -1387,3 +1387,13 @@ def test_default_latex_documents():
|
|||||||
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
expected = [('index', 'stasi.tex', 'STASI™ Documentation',
|
||||||
r"Wolfgang Schäuble \& G'Beckstein.\@{}", 'manual')]
|
r"Wolfgang Schäuble \& G'Beckstein.\@{}", 'manual')]
|
||||||
assert default_latex_documents(config) == expected
|
assert default_latex_documents(config) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@skip_if_requested
|
||||||
|
@skip_if_stylefiles_notfound
|
||||||
|
@pytest.mark.sphinx('latex', testroot='latex-includegraphics')
|
||||||
|
def test_includegraphics_oversized(app, status, warning):
|
||||||
|
app.builder.build_all()
|
||||||
|
print(status.getvalue())
|
||||||
|
print(warning.getvalue())
|
||||||
|
compile_latex_document(app)
|
||||||
|
Loading…
Reference in New Issue
Block a user