[Tex/LaTex] Trim, crop, and resize picture

graphicstikz-pgf

Because a picture is worth a thousand words, here it is:

enter image description here

If you prefer words, I'd like to do some resize and crop on a picture relative to a given "box dimension". To do so I'd like to do three things:

  1. put the picture inside the box, and extend it as much as possible : I can do it easily using the \includegraphics[width=..., height=...,keepaspectratio]
  2. do the contrary : change the size of the image such that she can fill the whole box, but such that the picture stay as small as possible
  3. in the same idea, do the same thing as the point 2, but crop the picture so that only the part of the picture that fit inside the box is visible. I should be able to choose easily an anchor on the box and an anchor on the picture so that I can choose where the image is put in the box.

I'm pretty sure that I can do 3 if I've 2 by using tikz crop (maybe there is a better way to proceed ?), but I don't know how to efficiently do 2. I tried to look into the package adjustbox, but I can't find anything that help me, and because this function is so useful, it would be strange that no one before me tried to write something for that…

Any idea ? Thank you !

Best Answer

After lot's of pain, I finally came up with this solution. If you find a better/shorter way to proceed, at any point, please let me now !

\documentclass[]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\graphicspath{{photos/}} % on change la racine

% === Pictures ===
% \includeFitInsidePicture{<max width>}{<max height>}{<name>}
% Create the biggest picture whose size is at most <max width>
% and <max height>.
\newcommand{\includeFitInsidePicture}[3]{%
  \includegraphics[width=#1,height=#2,keepaspectratio]{#3}%
}

\makeatletter
\newsavebox{\mybox}
% \includeFitOutsidePicture{<min width>}{<max width>}{<name>}
% Create the smallest picture whose size is at least <min width>
% and <min height>.
\newcommand{\includeFitOutsidePicture}[3]{%
  \begingroup%
  \sbox{\mybox}{\includegraphics{#3}}%
  \dimen0=#1\relax%
  \dimen1=#2\relax%
  \dimen2=\wd\mybox\relax%
  \dimen3=\ht\mybox\relax%
  \dimen0=\dimexpr 1pt*\dimen0/\dimen1\relax%
  \dimen1=\dimexpr 1pt*\dimen2/\dimen3\relax%
  \ifnum\dimen0>\dimen1\relax%
  \includegraphics[width=#1]{#3}%
  \else%
  \includegraphics[height=#2]{#3}%
  \fi%
  \endgroup%
}
\makeatother

% \addCropPicture{<width>}{<height>}{<anchor box>}{<anchor picture>}{<name>}
% Create the smallest picture whose size is at least <min width>
% and <min height>, and crop the region outside the box such that the anchor
% of the picture <ancher picture> touch the anchor of the box <anchor box>.
% Most of the time you want <anchor box>=<anchor picture>
\newcommand{\addCropPicture}[5]{%
  \begin{tikzpicture}[inner sep=0pt]
    \edef\q{(mnode.#3)}
    \node[minimum width=#1, minimum height=#2,inner sep=0pt](mnode) at (0,0) {};
    \clip (mnode.south west) rectangle (mnode.north east);
    \node[anchor=#4,inner sep=0pt](picture) at \q
    {\includeFitOutsidePicture{#1}{#2}{#5}};
    % \node[draw,minimum width=#1, minimum height=#2,inner sep=0pt] at (0,0) {};
  \end{tikzpicture}%
}

\begin{document}
% Draw a box to show the bounding box size
\tikz\draw (0,0) rectangle (5cm,5cm) node[pos=.5] {Reference box};
% Fit outside
\includeFitOutsidePicture{5cm}{5cm}{simpson.jpg}\fbox{Fit outside}

% Fit inside
\includeFitInsidePicture{5cm}{5cm}{simpson.jpg}\fbox{Fit inside}

% Crop in different ways
\vspace{1cm}Crop using three different anchors:

\addCropPicture{5cm}{5cm}{north west}{north west}{simpson.jpg}
\addCropPicture{5cm}{5cm}{north}{north}{simpson.jpg}
\addCropPicture{5cm}{5cm}{north east}{north east}{simpson.jpg}

\end{document}

Output:

enter image description here

Related Question