Creating a multi-picture layout
Hello! Thanks for the package, it looks very interesting!
I would like to try creating travel photo-books with it and I would like to define some multi-image layouts to be used in selected pages. What I mean with it is that, for example, I would like a page to contain four images arranged in a grid, possibly with different sizes. I have started developing the simple command \Collage{outer-margin}{image-spacing}{image-1}{image-2}{image-3}{image-4}, which can produce something like this:
The white rectangle represents the page produced by LaTeX, while the grey frame is just needed to see the borders of the page.
I managed to build the command, but I am a bit uncertain of the way I did it. I had to create a page and insert 4 cells using "absolute positioning". The width of each image should be (page_width - bleed - 2* outer_margin - image_spacing) / 2, while the the height (page_height - 2*bleed - 2* outer_margin - image_spacing) / 2. The origin of the top-left image should be (outer_margin, bleed+outer_margin), and for the others I just need to shift one or both origins by image_spacing+image_width or image_spacing+image_height.
My doubts are:
- To obtain the width of the page, I tried using
\paperwidthbut it is larger than what I expected. Instead, it looks like the proper dimension is\blockwidth. Is this correct? - When I calculate the origin of the first picture, it looks like there is "something" missing in my calculations. After experimenting a bit, I think that my conclusion is that the origin has to be offset by
\bleed, both horizontally and vertically. I thought the coordinate system started on the top-left corner, but it looks like we need to offset it by this amount. Is my understanding correct? - I guess in general it's not clear to me what are the dimensions to use in general, and what they signify. As an example, why is paperwidth larger than the pdf size, what is
imageblockwidthused for, etc. I know there's info in the documentation, but I thought I understood them until I saw the results...
Here is a minimal (more or less) working example. To compile it, you just need to have an image named test in the same folder. I used Lenna's picture, it seemed appropriate!
\documentclass[%
layoutmode=block,
blockwidth=20cm,
blockheight=20cm,
imageblockwidth=1.0,
imageblockheight=1.0,
bleed=10mm,
final
]{photobook}
% Remove page numbering
\usepackage{nopageno}
% A font I like
\usepackage{palatino}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The following should eventually be moved into a package
% Dependencies
\usepackage{tikz}
\usepackage{pgfmath}
\usepackage[strict]{changepage}
\usepackage{ifdraft}
% Helper command to convert a value from points to the given unit.
\makeatletter
\def\convertto#1#2{\strip@pt\dimexpr #2*65536/\number\dimexpr 1#1}
\makeatother
% Print the given length, in cm.
\newcommand{\printcm}[1]{\convertto{cm}{\the#1}cm}
% Create a white box that shows the size (in cm) of the cell it box belongs to.
% This is meant for debugging purposes.
\newcommand{\cellsizebox}{\begin{tikzpicture}\node[draw,minimum width=\cellwidth,minimum height=\cellheight] at (0,0) {\shortstack{W: \printcm{\cellwidth}\\ H: \printcm{\cellheight}}};\end{tikzpicture}}
% Some lengths that I need inside the main macro.
\newlength{\CollageOffset}
\setlength{\CollageOffset}{\bleed}
\newlength{\CollageOuterMargin}
\newlength{\CollageImageSpacing}
\newlength{\CollageFirstWidth}
\newlength{\CollageSecondWidth}
\newlength{\CollageFirstHeight}
\newlength{\CollageSecondHeight}
% Main command: create a collage with four pictures of variable size.
% Usage:
% \CollageTwo{outer_margin}{outer_margin}{width_ratio}{height_ratio}{img1}{img2}{img3}{img4}
%
% Creates a collage with four pictures like this one:
%
% =-----------------------------------+
% = . . . . . . . . . . . . . . . . . |
% = . |
% = . |
% = +------+ +------------+ . |
% = | img1 | | img2 | . |
% = +------+ +------------+ . |
% = . |
% = +------+ +------------+ . |
% = | | | | . |
% = | img3 | | img4 | . |
% = | | | | . |
% = +------+ +------------+ . |
% = . |
% = . |
% = . . . . . . . . . . . . . . . . . |
% =-----------------------------------+
%
% In the image above, the outer frame represents the visible page in the
% produced pdf. The dotted frame is obtained by "shrinking" the page size by
% "\bleed" from all sides, except the gutter. The dotted frame is then shurk,
% this time in all four directions, by a margin equal to "outer_margin". The
% distance between all images is determined by outer_margin. Finally, the size
% of each image is calculated as follows. The remaining horizontal and vertical
% space for the images are respectively:
% W = page_width - bleed - 2*outer_margin - image_spacing
% H = page_width - 2*bleed - 2*outer_margin - image_spacing
% The sizes of the images are then calculated as:
% img1: width_ratio*W ; height_ratio*H
% img2: (1-width_ratio)*W ; (1-height_ratio)*H
% img3: width_ratio*W ; height_ratio*H
% img4: (1-width_ratio)*W ; (1-height_ratio)*H
%
% TODO: allow to set the image fill-type (fit, fill, etc?)
% TODO: key-value pairs with defaults (at least for the ratios!)
% TODO: change name!
\newcommand{\CollageTwo}[8]{%
\begin{page}%
% Give a name to the first two parameters of the macro.
\setlength{\CollageOuterMargin}{#1}%
\setlength{\CollageImageSpacing}{#2}%
%
% Calculate the size of each image using pgfmath.
\pgfmathparse{(\blockwidth - \bleed - 2\CollageOuterMargin - \CollageImageSpacing) * #3}%
\setlength{\CollageFirstWidth}{\pgfmathresult pt}%
\pgfmathparse{(\blockwidth - \bleed - 2\CollageOuterMargin - \CollageImageSpacing) * (1-#3)}%
\setlength{\CollageSecondWidth}{\pgfmathresult pt}%
\pgfmathparse{(\blockheight - 2\bleed - 2\CollageOuterMargin - \CollageImageSpacing) * (#4)}%
\setlength{\CollageFirstHeight}{\pgfmathresult pt}%
\pgfmathparse{(\blockheight - 2\bleed - 2\CollageOuterMargin - \CollageImageSpacing) * (1-#4)}%
\setlength{\CollageSecondHeight}{\pgfmathresult pt}%
%
% Calculate the coordinates of the origins. Make sure to properly handle
% even and odd pages.
\checkoddpage%
\def\collageX{\ifoddpage\else\bleed+\fi \CollageOffset+\CollageOuterMargin}%
\def\collageY{\CollageOffset+\bleed+\CollageOuterMargin}%
\def\collageXX{\collageX+\CollageFirstWidth+\CollageImageSpacing}%
\def\collageYY{\collageY+\CollageFirstHeight+\CollageImageSpacing}%
%
% Place the images if in final mode, or a box with the content size in
% cm, if in draft mode.
\begin{cell}{\collageX,\collageY}{\CollageFirstWidth}{\CollageFirstHeight}%
\ifdraft{\cellsizebox}{\imagecell[fill]{}{#5}}%
\end{cell}%
%
\begin{cell}{\collageXX, \collageY}{\CollageSecondWidth}{\CollageFirstHeight}%
\ifdraft{\cellsizebox}{\imagecell[fill]{}{#6}}%
\end{cell}%
%
\begin{cell}{\collageX, \collageYY}{\CollageFirstWidth}{\CollageSecondHeight}%
\ifdraft{\cellsizebox}{\imagecell[fill]{}{#7}}%
\end{cell}%
%
\begin{cell}{\collageXX, \collageYY}{\CollageSecondWidth}{\CollageSecondHeight}%
\ifdraft{\cellsizebox}{\imagecell[fill]{}{#8}}%
\end{cell}%
\end{page}%
}
% TODO: once the "CollageTwo" macro accepts the defaults for the ratio, remove this macro!
\newcommand{\Collage}[6]{\CollageTwo{#1}{#2}{0.5}{0.5}{#3}{#4}{#5}{#6}}
% Book information
\def\BookTitle{Foobar}
\def\BookAuthors{Franco Fusco}
\def\ThanksTo{Flynx}
\def\Edition{N/A}
\begin{document}
% Author and copyright information.
\BookInfoPage
% "Square" aspect ratio
\Collage{0cm}{0cm}{test}{test}{test}{test}
\Collage{0cm}{0.5cm}{test}{test}{test}{test}
\Collage{1cm}{0cm}{test}{test}{test}{test}
\Collage{1cm}{0.5cm}{test}{test}{test}{test}
% Non-square aspect ratio
\CollageTwo{0cm}{0cm}{0.6}{0.6}{test}{test}{test}{test}
\CollageTwo{0cm}{0.5cm}{0.6}{0.6}{test}{test}{test}{test}
\CollageTwo{1cm}{0cm}{0.6}{0.6}{test}{test}{test}{test}
\CollageTwo{1cm}{0.5cm}{0.6}{0.6}{test}{test}{test}{test}
% Full bleed
\CollageTwo{-\bleed}{0cm}{0.6}{0.6}{test}{test}{test}{test}
\CollageTwo{-\bleed}{0.5cm}{0.6}{0.6}{test}{test}{test}{test}
\end{document}
Hi,
Seems that you have already figured out most of it.
I'll try and fill in the blanks:
- All sizes in LaTeX are indeed relative to the "page",
- LaTeX has no concept of bleeds (i.e. bleeds are non-existent / 0pt),
-
geometry's\paperwidth/\paperheightare the size of the paper, how LaTeX sees it (with bleeds), before it is cut to size, whilephotobook's\blockwidth/\blockheightare the size of the final block in the finished book, i.e. without the bleeds an binding offset but including the gutter offset (see: "Page geometry" in the docs (updated the docs to reflect this better), -
\bindingoffsetsets the "bleed" in the gutter (love how this sounds out of context ;) ) of the page -- it is separate form\bleedas it can be handled/set a bit differently from the normal bleeds depending on the bind type, -
photobooksets the bleeds within the LaTeX's page so as not to break any packages that align relative to the page and might need to be printed full bleed, and to avoid any trimming of content outside the "page" that may occur, - In PDF, bleeds are implemented as boxes and are used by the printer to align the paper for printing, binding, to "cut off" the bleeds after binding the block, and by pdf viewers and editors to show you the final page as it would be seen in paper form (see pdf's
/MediaBox,/BleedBox,/ArtBox,/TrimBox, and/CropBoxandphotobook's\pdfboxesset[..]{..}{..}command, though this is mostly for reference and for the very uncommon case where you would want to do something really low-level / exotic asphotobooktakes care of this internally). - To make things simpler
photobookdefines thepapercellenv to position cells relative to the final page -- the naming might be a bit confusing if you add thegeometrypackage into the mix, but withinphotobookit is needed to differentiate the physical page (paper) and the logical pages, for example: a single foldout "page" can include multiple logical pages, while a simple page in the general case is both a physical page and a logical page. See: "Paper cells" vs. "Page cells" in the docs (might need to rethink naming again).
Looking at how you organized your code, if you are aiming for a generic command, usable in different projects, I'd suggest a less absolute approach if possible, here's a basic example: https://github.com/flynx/photobook/blob/main/examples/two-image-page.tex
Also, do not forget that \bindingoffset is used instead of \bleed in the gutter so you'll have to also make your command page-position-aware if you are positioning things absolutely.
And in the general case you should also account for \gutteroffset to make things more compatible with photobook macros/commands/envs -- it is used to shift page content relative to the page gutter to account for different binding types.
IMHO, it would be far simpler to actually position your content relative to the containing cell, this way you can use any of the existing cells as containers to place your "element" in any way you want (including recursively), be it full bleed or with the same geometry as a text block, for example... and implement your page templates on top of that. This way photobook will take care of all the details like bleeds and page offsets so you can forget they ever existed (see the available container cells defined by photobook) ...I was planning on implementing a grid cell but was procrastinating, putting it off till the next book project, but I was thinking of a more generic approach, though that would be quite a bit more tedious than what you are doing =)
Cheers)
Ok, I think that now I understand my... misunderstanding! Basically, the bleed is invisible in the pdf viewer, but it is there. The red rectangle in the picture I attached is actually the visible page already. And the margin I have added in the internal part should be "manually" offset by the gutter and binding offset as needed - since I am using "absolute positioning".
So to make it clear (at least to me) the snippet
\begin{page}
\begin{cell}{0pt, 0pt}{\paperwidth}{\paperheight}
\imagecell{}{img.jpg}
\end{cell}
\end{page}
creates a "full page image" that is "good" for printing and cutting. If I used just \begin{cell}{\bleed, \bleed}{\blockwidth}{\blockheight} the pdf would have been ok but printing is troublesome - because I am not bleeding.
That said, I still have a couple of questions. I'll post them in separate comments to make them more digestible.
First of all, you suggested to use inline cells. However, I am having issues. I tried to write the following:
\documentclass[%
layoutmode=block,
blockwidth=22cm,
blockheight=20cm,
imageblockwidth=1.0,
imageblockheight=1.0,
bindingoffset=1cm,
gutteroffset=1cm,
bleed=5mm,
final
]{photobook}
\begin{page}
\begin{pagecell}
\begin{inlinecell}{10cm}{10cm}
\imagecell{}{square}
\end{inlinecell}
\begin{inlinecell}{10cm}{10cm}
\imagecell{}{square}
\end{inlinecell}
\begin{inlinecell}{10cm}{10cm}
\imagecell{}{square}
\end{inlinecell}
\begin{inlinecell}{10cm}{10cm}
\imagecell{}{square}
\end{inlinecell}
\end{inlinecell}
\end{page}
I would have expected to see four squares "nicely arranged" next to each other. However, this is the result:
Do you have an idea why the four images are not stacked nicely?
Second issue. I was trying to understand how to make my code cleaner, and I read in the manual that cell environments "register" their offset - allowing to "locate" them so to speak. For this, here you use \setlength\celloffsettop{\photobook@cell@offset[1]}. Shouldn't it be \celloffsetleft that is updated here? I assume that the offset in \photobook@cell@offset[1] is (x, y), maybe that's my mistake.
Also, I am trying to use the \celloffsetleft parameter to position cells relative to each other, but still using cell instead of inlinecell. I tried the following:
\begin{page}
\begin{cell}{\bleed,\bleed}{\paperwidth}{\paperheight}
\begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm}
\imagecell{}{square}
\begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm}
\imagecell{}{square}
\begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm}
\imagecell{}{square}
\end{cell}
\end{cell}
\end{cell}
\end{cell}
\end{page}
Which, to my understanding, should be able to repeat the picture while shifting it towards the bottom right corner. However, this is not the case. What happens is that the picture is shifted only once towards the right. Any idea why this may be happening?
Finally, I encountered a problem while working with "real" images - instead of the test one, that was just 512x512. When using "large" images I encounter an Arithmetic overflow error. Here is an example to reproduce it with this picture:
\documentclass[%
layoutmode=block,
blockwidth=20cm,
blockheight=20cm,
imageblockwidth=1.0,
imageblockheight=1.0,
bleed=2mm,
final
]{photobook}
\begin{document}
% IMAGE CREDITS
% Photo by Mohamed Almari from Pexels: https://www.pexels.com/photo/golden-gate-bridge-san-francisco-1591382/
\begin{page}
\begin{cell}{2cm, 1cm}{10cm}{15cm}
\imagecell[fill]{}{image.jpg}
\end{cell}
\end{page}
\end{document}
@francofusco
\documentclass[% layoutmode=block, blockwidth=22cm, blockheight=20cm, imageblockwidth=1.0, imageblockheight=1.0, bindingoffset=1cm, gutteroffset=1cm, bleed=5mm, final ]{photobook} \begin{page} \begin{pagecell} \begin{inlinecell}{10cm}{10cm} \imagecell{}{square} \end{inlinecell} \begin{inlinecell}{10cm}{10cm} \imagecell{}{square} \end{inlinecell} \begin{inlinecell}{10cm}{10cm} \imagecell{}{square} \end{inlinecell} \begin{inlinecell}{10cm}{10cm} \imagecell{}{square} \end{inlinecell} \end{inlinecell} \end{page}
Don't know how you managed to build this without a document but...
Here's a working version ;)
\documentclass[%
layoutmode=block,
blockwidth=22cm,
blockheight=20cm,
imageblockwidth=1.0,
imageblockheight=1.0,
bindingoffset=1cm,
gutteroffset=1cm,
bleed=5mm,
final
]{photobook}
\begin{document}%
%
\begin{page}%
\begin{pagecell}%
\begin{inlinecell}{10cm}{10cm}%
\imagecell{}{square}%
\end{inlinecell}%
\begin{inlinecell}{10cm}{10cm}%
\imagecell{}{square}%
\end{inlinecell}%
\newline%
\begin{inlinecell}{10cm}{10cm}%
\imagecell{}{square}%
\end{inlinecell}%
\begin{inlinecell}{10cm}{10cm}%
\imagecell{}{square}%
\end{inlinecell}%
\end{pagecell}%
\end{page}%
%
\end{document}
@francofusco
Ok, I think that now I understand my... misunderstanding! Basically, the bleed is invisible in the pdf viewer, but it is there. The red rectangle in the picture I attached is actually the visible page already. And the margin I have added in the internal part should be "manually" offset by the gutter and binding offset as needed - since I am using "absolute positioning".
So to make it clear (at least to me) the snippet
\begin{page} \begin{cell}{0pt, 0pt}{\paperwidth}{\paperheight} \imagecell{}{img.jpg} \end{cell} \end{page}creates a "full page image" that is "good" for printing and cutting. If I used just
\begin{cell}{\bleed, \bleed}{\blockwidth}{\blockheight}the pdf would have been ok but printing is troublesome - because I am not bleeding.
Yep =)
@francofusco
\begin{page} \begin{cell}{\bleed,\bleed}{\paperwidth}{\paperheight} \begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm} \imagecell{}{square} \begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm} \imagecell{}{square} \begin{cell}{\celloffsetleft+\bleed,\celloffsettop+\bleed}{10cm}{10cm} \imagecell{}{square} \end{cell} \end{cell} \end{cell} \end{cell} \end{page}
This I'll have to investigate a bit deeper, might be a bug... (I've not touched the code here for some time)
@francofusco
Finally, I encountered a problem while working with "real" images - instead of the test one, that was just 512x512. When using "large" images I encounter an
Arithmetic overflowerror. Here is an example to reproduce it with this picture:
The link you included returns an empty JSON object, at least for me...
How large was the image? (pixel size, dpi, color depth)
Don't know how you managed to build this without a
documentbut...
Because I'm the god of LaTeX of course! 😃 Jokes aside, I think I messed something while re-formatting it here in the issue, since the original script that contains the page is a bit longer. I confirm that the snippet as you posted it works as intended, so it must be my tinkering that has messed up something. I'll try to understand the root of the issue and report back if needed!
@francofusco
Finally, I encountered a problem while working with "real" images - instead of the test one, that was just 512x512. When using "large" images I encounter an
Arithmetic overflowerror. Here is an example to reproduce it with this picture:The link you included returns an empty JSON object, at least for me...
How large was the image? (pixel size, dpi, color depth)
Ah that's weird. For me it redirects to a page where you can see the image below:
The resolution is 5304x6630. I just tested it to make sure the issue is not (again) caused by my tinkering - and indeed, I think I'm innocent this time!
\documentclass[%
layoutmode=block,
blockwidth=20cm,
blockheight=20cm,
imageblockwidth=1.0,
imageblockheight=1.0,
bleed=2mm,
final
]{photobook}
\begin{document}
\ImagePageClear{}{images/goldenbridge} % This is ok!
\ImagePageFill{}{images/goldenbridge} % This fails :(
\end{document}
Finally, I encountered a problem while working with "real" images - instead of the test one, that was just 512x512. When using "large" images I encounter an
Arithmetic overflowerror. Here is an example to reproduce it with this picture:
OK, seems that I can reproduce this with image of height over 3989px and/or width over 4999px.... really odd....
UPDATE: do not see anything obvious, will have to dig in deeper)
I don't want to say something stupid, but if I remember correctly, LaTeX uses (I want to say) 16 bits for numbers, which is not a lot (2^16 is about 65k). Maybe in some calculations the limit is reached, that would make sense given the type of error.
2^16
Yes, an overflow somewhere is the primary hypothesis here, but what's confusing (or rather it's fun) is both the different thresholds for height and width and the distance between 216 and these values, especially considering the math involved =)
UPDATE: found the culprit \ratio{3395.67801pt}{5018.73784pt} though not yet sure why it's breaking, need to get some sleep first =)
UPDATE: Published a workaround: 1508055cf3170cec299d3fb210829b0c0561eab8 (v0.1.31) -- see Issues section in docs.