Making the text fit in a specific space in Latex

REVISED ANSWER (FULLY AUTOMATED):

In this revised answer, one calls on \constraintext, passing it five arguments:

#1 The constrained text height

#2 the constrained text width

#3 the text content to constrain

#4 a guess larger than or equal to the natural (unscaled) width of the content (picking too large will just cause a few extra iterations)

#5 the positive increment of length that will be subtracted off the natural width with each iteration, in search of satisfying the desired aspect ratio.

As alluded to, an unscaled \parbox is created (in the current fontsize) using the natural width (input #4) as the boxwidth. The aspect ratio is tested. If you've selected #4 large enough, the aspect ratio will be below the target value. Then, the unscaled box is made narrower by an amount given in #5 and the aspect ratio is retested. It will be increasing relative to the prior test. This process is recursively repeated until the tested aspect ratio equals or exceeds the target value.

At that point, the box may be set to the constrained height (#1), with the \parbox width remaining at or slightly below the constrained width. The padding is accomplished with matched \hfills to make the typeset width equal to the constrained width.

I have placed notes in the MWE on what to comment to remove diagnostic printing.

\documentclass{article}
\usepackage{scalerel}
\usepackage{fp}
\usepackage{lipsum}
\usepackage{stackengine}
\newcount\boxheight
\newcount\boxwidth
\newlength\constrainedwidth
\newsavebox\testbox
\newlength\currentwidth

\newcommand\aspect[1]{%
  \boxheight=\ht#1\relax%
  \boxwidth=\wd#1\relax%
  \FPdiv\testaspect{\the\boxheight}{\the\boxwidth}%
\testaspect\\%                  COMMENT THIS LINE TO REMOVE ASPECT-RATIO PRINTS
}
% TARGET-HEIGHT, TARGET-WIDTH, CONTENT, GUESS>NATURAL-WIDTH, dWIDTH
\newcommand\constraintext[5]{%
  \def\svfboxsep{\the\fboxsep}%
  \setlength\fboxsep{0pt}%
  \setlength\constrainedwidth{#2}%
  \sbox\testbox{\rule{#2}{#1}}%
TARGET ASPECT RATIO\\%          COMMENT THIS LINE TO REMOVE COMMENT
V\\%                            COMMENT THIS LINE TO REMOVE COMMENT
  \aspect{\testbox}%
  \edef\aspectratio{\testaspect}%
  \constrainsize{#1}{\aspectratio}{#3}{#4}{#5}%
  \setlength\fboxsep{\svfboxsep}%
}
\newcommand\constrainsize[5]{%
  \sbox{\testbox}{\fbox{\parbox[b]{#4}{#3}}}%
  \aspect{\testbox}%
  \FPiflt{\testaspect}{#2}%
    \setlength{\currentwidth}{#4}%
    \addtolength{\currentwidth}{-#5}%
    \constrainsize{#1}{#2}{#3}{\currentwidth}{#5}%
  \else
    \setlength\constrainedwidth{#1}%
    \FPdiv\result{1.0}{#2}%
%                               CHANGE \framebox TO \makebox TO REMOVE FRAME
    \framebox[\result\constrainedwidth]{\hfill%
      \scaleto{\parbox[b]{\currentwidth}{#3}}{#1}%
      \hfill%
    }%
  \fi%
}
\parindent 0in
\begin{document}
\constraintext{5in}{2.8in}{\lipsum[1-2]}{3in}{.02in}
\rule[-\fboxsep]{.2ex}{5in}\\
\rule{2.8in}{.2ex}
\clearpage
\constraintext{5in}{2.8in}{\lipsum[3]}{2.25in}{.02in}
\rule[-\fboxsep]{.2ex}{5in}\\
\rule{2.8in}{.2ex}
\end{document}

Two results are shown below, with different sized input streams, but both set to the same size (5in x 2.8in) final box. Rules are set beside and below the boxes to confirm the accuracy of the box sizes.

Diagnostics are shown, giving first the target aspect ratio, and then the aspect ratio with each iteration. When the aspect ratio junps suddenly, it indicates that the typeset box required an additional line of text, due to wrapping. The closer the final aspect ratio is to the target, the less horizontal padding is required to constrain the box.

enter image description here

enter image description here

ORIGINAL ANSWER (NOT FULLY AUTOMATED):

This isn't fully automated, but with a little iteration, gets the job done. Let's say you wanted to put the first two lipsum paragraphs into a box that is 5 inches high by 2 inches wide. That works out to a height/width aspect ratio of 2.5. I started by placing those paragraphs into a framed \parbox and (here's the iteration) playing with the box width to achieve the right aspect ratio, using my handy \aspect macro (it took me about 4 iterations and maybe a minute for this iterative phase of it).

Once I achieved a result of 2.5+/-epsilon aspect, I then used a \scaleto from the scalerel package to scale the box to a 5 inch height. The aspect ratio guarantees it to be a 2 in width. I show the original 10pt typeset box (\x) and its scaled companion.

\documentclass{article}
\usepackage{scalerel}
\usepackage{fp}
\usepackage{lipsum}
\newcount\boxheight
\newcount\boxwidth
\newcommand\aspect[1]{%
  \boxheight=\ht#1\relax%
  \boxwidth=\wd#1\relax%
  \FPdiv\result{\the\boxheight}{\the\boxwidth}\result%
}
\begin{document}
\newsavebox\x
\sbox{\x}{\fbox{\parbox[b]{2.42in}{\lipsum[1-2]}}}
\aspect{\x}

\usebox{\x}
\scaleto{\usebox{\x}}{5in}    
\end{document}

enter image description here

And as to the layout of your particular sample image, I re-evaluated that aspect ratio to 1.75 as my target (resulting in a paragraph size 5" x 20/7"), and came up with this, where my \rules can be replaced with \includegraphics. Of course, my 5in height is just a guess, but that's amendable.

\documentclass{article}
\usepackage{scalerel}
\usepackage{fp}
\usepackage{lipsum}
\usepackage[oldsyntax]{stackengine}
\newcount\boxheight
\newcount\boxwidth
\newcommand\aspect[1]{%
  \boxheight=\ht#1\relax%
  \boxwidth=\wd#1\relax%
  \FPdiv\result{\the\boxheight}{\the\boxwidth}\result%
}
\begin{document}
\newsavebox\x
\sbox{\x}{\fbox{\parbox[b]{2.84in}{\lipsum[1-2]}}}
%\aspect{\x}

\def\hgp{\hspace{.1in}}
\def\plotA{\protect\rule{1.36in}{0.66in}}
\def\plotB{\protect\rule{1.36in}{1.36in}}
\def\plotC{\protect\rule{1.36in}{1.36in}}
\def\plotD{\protect\rule{1.36in}{1.36in}}
\def\plotE{\protect\rule{1.36in}{1.36in}}
\def\plotF{\protect\rule{1.36in}{1.36in}\hgp}
\def\plotG{\protect\rule{1.36in}{1.36in}}

\def\stackalignment{l}
\Sstackgap=.1in
\Shortstack{{\plotA} {\plotB} {\plotC} {\plotD} {\plotE}}\hgp%
\stackon{\plotF \plotG}{\scaleto{\usebox{\x}}{5in}}

\end{document}

enter image description here

p.s. I'm using V2.0 stackengine, which you might not have yet. Until you're able to upgrade, and in order to get the 2nd MWE working, just remove the [oldsyntax] package option.


\tcolorbox includes library fitting with its command \tcboxfit. It fits its content inside a box of given width and height.

Next some examples:

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{lipsum}
\usepackage{lmodern}

\tcbset{colframe=blue!50!black,colback=green!10!white,
boxsep=0pt,top=1mm,bottom=1mm,left=1mm,right=1mm,
nobeforeafter, arc=0pt, outer arc=0pt}

\begin{document}

\lipsum[1]

\noindent\tcboxfit[width=.5\linewidth,height=6cm]{\lipsum[1]}
\hfill
\tcboxfit[width=.45\linewidth, height=4cm]{\lipsum[1]}

\noindent\tcboxfit[width=\linewidth, height=2cm]{\lipsum[1]}

\end{document}

enter image description here

Tags:

Boxes

Fit