How to get the aspect ratio of an image programmatically

How can I get the aspect ratio of an image and store it in a pgf macro for further calculations? For example:

\documentclass{article}

\usepackage{graphicx}
\usepackage{tikz}

\begin{document}

\includegraphics{image.jpg}

\begin{tikzpicture}
\pgfmatsetmacro{\aspectratio}{???} % This variable should contain the aspect ratio of image.jpg
\end{tikzpicture}
\end{document}

• Put the image in a box, then the aspect ratio is the (total) height vs width of that box. – daleif Sep 4 '17 at 10:24

Here is an \aspectratio macro that either prints the aspect ratio or stores it in a macro given as optional argument. The *-form will do a global assignment, in case you need it. The macro (in the example it is \test) can be used in \pgfmathsetmacro or other environment accepting floating point numbers.

\documentclass{article}
\usepackage{graphicx}

\ExplSyntaxOn
\NewDocumentCommand{\aspectratio}{smo}
{% #2 is the image file
\hbox_set:Nn \l_tmpa_box {\includegraphics{#2}}
\IfNoValueTF{#3}
{
\__student_aspectratio:nn { \box_wd:N \l_tmpa_box } { \box_ht:N \l_tmpa_box }
}
{
\IfBooleanTF{#1}{ \tl_gset:Nx } { \tl_set:Nx } #3
{
\__student_aspectratio:nn { \box_wd:N \l_tmpa_box } { \box_ht:N \l_tmpa_box }
}
}
}

\cs_new:Nn \__student_aspectratio:nn
{
\fp_eval:n {round( #1 / #2 , 5)}
}
\ExplSyntaxOff

\begin{document}

\aspectratio{example-image}

\aspectratio{example-image-1x1}

\begingroup
\aspectratio*{example-image-9x16}[\test]
\endgroup

\texttt{\meaning\test}

\end{document}


In pdftex you can use the register \pdfximagebbox to retrieve the coordinates of the bounding box. These are

The width and height of the image are obviously given by

width  = [upper-right x] - [lower-left x]
height = [upper-right y] - [lower-left y]


and the aspect ratio is simply width/height. Using the xfp package to evaluate the floating point expression, the following document prints 1.333... underneath the image (which has an aspect ratio of 4:3, so it's correct).

\documentclass{article}
\usepackage{graphicx,xfp}
\begin{document}

\includegraphics{example-image-a}

\fpeval{
(\pdfximagebbox\pdflastximage 3 - \pdfximagebbox\pdflastximage 1)
/
(\pdfximagebbox\pdflastximage 4 - \pdfximagebbox\pdflastximage 2)
}

\end{document}

• I get the following error: \LaTeX3 error: Invalid operation (0)/(0) – student Sep 4 '17 at 12:22
• @student It only works in pdftex (just guessing). – Henri Menke Sep 4 '17 at 12:27
• I used pdflatex – student Sep 4 '17 at 12:31

Here's a trick using \newcount registers to store length.

\documentclass{article}
\usepackage{graphicx}
\usepackage{fp}
\newcount\boxheight
\newcount\boxwidth
\newcommand\testaspect[1]{%
\setbox0=\hbox{#1}%
\boxheight=\ht0\relax%
\boxwidth=\wd0\relax%
\FPdiv\theaspect{\the\boxheight}{\the\boxwidth}%
\copy0%
}
\begin{document}
\testaspect{\includegraphics{example-image}}

The aspect ratio is \theaspect.

\testaspect{A}

The aspect ratio is \theaspect.

\testaspect{\tiny A}

The aspect ratio is \theaspect.
\end{document}


• Thanks. I for my actual problem the image is inside of a \node[inner sep = 0pt] at (0,0) {\testaspect{\includegraphics{image}}} construction and I need the aspectratio outside of this (in but in the same tikzpicture environment). In this case your solution doesn't work. Any idea? – student Sep 4 '17 at 12:45
• @student In my \testaspect macro, after the \FPdiv invocation, you should be able to \global\let\theaspect\theaspect to make \theaspect a global variable. – Steven B. Segletes Sep 5 '17 at 1:11

If node dimensions are needed, tcolorbox macros \tcbsetmacrotowidthofnode and \tcbsetmacrotoheighthofnode can get it and the result be used in other nodes on same tikzpicture. These macros are explained in section Extracting node dimensions (page 263 in v4.10 and page 253 in v4.02).

\documentclass{article}
\usepackage[most]{tcolorbox}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}
\node[inner sep=0pt, outer sep=0pt] (A) {\includegraphics[width=145pt]{example-image}};
\tcbsetmacrotowidthofnode\mywidth{A}
\tcbsetmacrotoheightofnode\myheight{A}
\node[below = 3mm of A] (width) {The width of this figure is \the\numexpr\mywidth};
\node[below = 5mm of width] (height) {The height of this figure is \myheight};
\node[below = 5mm of height] (aspect) {The aspectratio of this figure is \pgfmathparse{\mywidth/\myheight}\pgfmathresult};

\node[draw, minimum width=\mywidth, minimum height=\myheight, right=1mm of A]{};
\end{tikzpicture}
\end{document}


Macro \SetToRatio from https://tex.stackexchange.com/a/383700/4686

\documentclass{article}

\usepackage{graphicx}
%\usepackage{tikz}

\newsavebox\mybox

% https://tex.stackexchange.com/a/383700/4686
\makeatletter
\newcommand\SetToRatio[3]{% sets #1 to be the ratio #2/#3, where #2 and #3
% are lengths (registers or expressions).
% The ratio #2/#3 should evaluate to less than 16384 in absolute value to
% avoid arithmetic overflow. It will be computed as fixed point
% number with about 4 or 5 digits after decimal mark.
\edef #1%
{\strip@pt\dimexpr
\numexpr\dimexpr#2\relax*65536/\dimexpr#3\relax\relax sp\relax}%
}
\makeatother
\begin{document}

\sbox{\mybox}{\includegraphics[draft]{example-image.pdf}}
% you may prefix this with \global if executed within scope limiting location
\SetToRatio\aspectratio{\dimexpr\ht\mybox+\dp\mybox\relax}{\wd\mybox}

% debugging
% \show\aspectratio

% now use it !
%\begin{tikzpicture}
%\pgfmatsetmacro{\aspectratio}{???} % This variable should contain the aspect ratio of image.jpg
%\end{tikzpicture}
\end{document}