[Tex/LaTex] Size image by area

graphics

Sometimes I have to insert many relatively small different images, with different aspect ratio, which widths must be adjusted one by one in order to look approximately of the same size.

In such cases it would be useful to be able to size the image by area, that is choose the area and let LaTeX set image width or height so that width x height = area (keeping aspect ratio).

The ideal would be a new command built upon \includegraphics able to accept an area parameter (square root of area would be even better, because in order to get a sense of the size of the area you usually end up in calculating its square root). Such a command, given for example two images img_a (having aspect ratio W:H=2:1) and img_b (having aspect ratio W:H=2:3), with the following code

\includegraphicsbyarea[area=18]{img_a} % suppose area in square centimeters
\includegraphicsbyarea[area=18]{img_b}
\includegraphicsbyarea[area=32]{img_a}

would insert:

  • img_a with width of 6 cm and height of 3 cm (6×3=18, 6:3=2:1)
  • img_b with width of 3.464 cm and height of 5.196 cm (3.464×5.196=18, 3.464:5.196=2:3)
  • img_a with width of 8 cm and height of 4 cm (8×4=32, 8:4=2:1)

Would it be possible?

Thanks in advance for any clue.

Best Answer

Here is an approach not redefining \includegraphics. However compared to scale option, I cut a branch because I don't have details of graphicx.sty in head, so possibly there would be a way to delegate to driver the final rescaling, which I am losing here. Ping @DavidCarlisle.

(I use xintexpr but xfp of course would do it as well as in Joseph's answer; also, up to some more cumbersome notations one could use only the macros of xintfrac, giving a tiny speed-up as expression parsing is skipped).

\documentclass{article}
\usepackage{graphicx}
\usepackage{xintexpr}
\makeatletter
\define@key{Gin}{sqrtofarea}{%
    \def\Gin@req@sizes{%
      \edef\Gin@scalex{\xinttheiexpr[5]% round fixed point to 5
                                       % fractional digits
                       \dimexpr#1\relax/
                            sqrt(\Gin@nat@height*\Gin@nat@width)
                       \relax}%
      \let\Gin@scaley\Gin@exclamation
      \Gin@req@height\Gin@scalex\Gin@nat@height
      \Gin@req@width\Gin@scalex\Gin@nat@width
      }%
  \@tempswatrue}
\makeatother
\begin{document}

\includegraphics[sqrtofarea=2cm]{example-image-a}

\includegraphics[sqrtofarea=3cm]{example-image-a}

\includegraphics[sqrtofarea=4cm]{example-image-a}

\includegraphics[sqrtofarea=5cm]{example-image-a}

\newbox\mybox
Equality only expected up to 5 digits of precision due to intrinsic
limitations of graphicx computations.

\setbox\mybox\hbox{\includegraphics[sqrtofarea=2cm]{example-image-a}}%

\xinttheiiexpr\ht\mybox*\wd\mybox\relax
?=
\xinttheiiexpr\dimexpr2cm\relax*\dimexpr2cm\relax\relax\ (4cm$^2$)

\setbox\mybox\hbox{\includegraphics[sqrtofarea=5cm]{example-image-a}}%

\xinttheiiexpr\ht\mybox*\wd\mybox\relax
?=
\xinttheiiexpr\dimexpr5cm\relax*\dimexpr5cm\relax\relax\ (25cm$^2$)
\end{document}

enter image description here


The sentence at bottom of image must be amended: in TeX all dimensions are integer multiples of 1sp. When we set the area square root as key, we automatically limit the achievable precision of the area. For example 5cm internally in TeX gives 9323399sp, hence a square equal to 86925768913201 as in image above. The previous square is 86925750266404 and the next one is 86925787560000, so they diverge in the 7th digit already and we can never overcome that possible imprecision when comparing a square with a produce height times width. Above we observe discrepancy already in 5th digit so the sentence is probably not completely wrong, but I felt I needed to add this mathematical precision.


Here is same with xfp (basically copied from Joseph's way of using it):

\documentclass{article}
\usepackage{graphicx}
\usepackage{xfp}
\makeatletter
\define@key{Gin}{sqrtofarea}{%
    \def\Gin@req@sizes{%
      \edef\Gin@scalex{\fpeval{#1/sqrt(\Gin@nat@height*\Gin@nat@width)}}%
      \let\Gin@scaley\Gin@exclamation
      \Gin@req@height\Gin@scalex\Gin@nat@height
      \Gin@req@width\Gin@scalex\Gin@nat@width
      }%
  \@tempswatrue}
\makeatother
\begin{document}

\includegraphics[sqrtofarea=2cm]{example-image-a}

\includegraphics[sqrtofarea=3cm]{example-image-a}

\includegraphics[sqrtofarea=4cm]{example-image-a}

\includegraphics[sqrtofarea=5cm]{example-image-a}

\end{document}

About this:

  • no wrapping of #1 in \dimexpr #1\relax needed here; xintexpr could easily be extended to recognize cm, in, pt, etc ... units so that e.g. 2cm is understood automatically, but the problem is that it would then do an exact conversion to a fractional number of sp units, whereas TeX process is more complex than simply using a proportionality factor and proceeds with rounding and truncating in various directions at various stages; so using exact conversion factor means not doing same operations as TeX itself. For this reason, no such units are defined yet in xintexpr and user must go via \dimexpr #1\relax; the xintexpr parser will apply \number to this, triggering TeX's own way to convert dimensional units.

  • I am not expert in xfp so I don't know if sometimes such computation could result in a scientific notation which would break TeX later; in the xintexpr solution I applied a transformation to fixed point value with 5 fractional digits. I don't know how one does that in xfp and whether it could be needed here in some cases. In the MWE above it works fine.

Related Question