45

in some (very rare) cases, it might be desirable to have the type area, particularly the text width, be different on even and odd pages. Let's say we're typesetting a textbook that's supposed to have small illustrations or annotations in the margin of the odd pages -- so we'd need a narrower type area on these. Like this:

different type areas even/odd Here's an attempt at a solution I came up with. It isn't as smart as I thought it was. I thought we might just combine everyshi and an \ifthispageodd test to change the typearea at every shipout. Obviously, that's not how it works:

\documentclass[paper=a5,pagesize,10pt,DIV=12,twoside=true]{scrreprt}
\usepackage{everyshi,blindtext}
\EveryShipout{%
\ifthispageodd{\areaset{6cm}{12cm}}{\areaset{9cm}{12cm}}}

\begin{document}
\Blinddocument
\end{document}

this results in:

! Bad space factor (0).
<recently read> \@savsf 

l.7 \Blinddocument

Is there a way to improve this? Or something entirely different?

Nils L
  • 9,716
  • 6
    At the very least, this is highly non-trivial because of the asynchronous manner in which TeX works. Page breaking happens separately from paragraph building, and feeding information from the latter into the former will require some very advanced TeX hackery indeed. I am not saying it can't be done, however … Maybe I should say so, to provoke someone into proving me wrong. – Harald Hanche-Olsen Feb 20 '13 at 15:32
  • 12
    It is massively complicated to do this in TeX, you need to save the entire paragraph (for each paragraph) then you need to detect how far into the paragraph the page break happens and then re-set the paragraph with a parshape that uses wide lines for n-lines and short lines for the rest. It gets more complicated still if you allow paragraphs longer than a page as then you need a \parshape that chages the length at each break. – David Carlisle Feb 20 '13 at 15:40
  • That's about what I expected. I know the paragraph building and page breaking are interrelated in a way that makes this enterprise a bit difficult (which is why I wasn't too surprised my solution didn't work that way). Another thing I had in mind is the flowfram package, but I've never used it and don't know enought about it (yet) to tell if it's of any use here. Maybe someone does? – Nils L Feb 20 '13 at 15:40
  • In the hope of easing your angst, a simple question: why would you not want small illustrations or annotations in the margins of even pages, too? – Brent.Longborough Feb 20 '13 at 16:06
  • 2
    I've asked that kind of question many times myself, in reply to people asking if x is possible in *TeX: »why do you want that in the first place? You might as well stop wanting it and be a happier wo/man«. But then again, if DE Knuth had been given that answer in the 70s when he asked if x is possible in phototypesetting, and if he had followed that advice and kept the things he wanted within the constraints of what's possible, we'd probably still be using Linotrons. As for my angst: it isn't that bad. It's a fictitious scenario, fortunately. I'd like know if it were possible and at what cost. – Nils L Feb 20 '13 at 16:35
  • 1
    That's so true... – Brent.Longborough Feb 20 '13 at 20:11
  • 1
    @NilsL In the flowfram manual the first point of section 8.2 answers your question. In short flowfram runs into the same problem. – StrongBad Feb 25 '13 at 15:58
  • 10
  • It seems to me that this may result in a document that will never be typeset properly. For example, suppose on the even LaTeX runs a float is moved from Page X (an odd page) to Page Y (an even page). On the odd LaTeX runs, the same float may be moved back from Page Y to Page X. All this moving to and fro may be caused by space restrictions on the even/odd pages that have different sizes. I mentioned the document will never be typeset properly because the relevant list of floats will always be incorrect. –  Apr 07 '13 at 10:21
  • 1
    There are some comments to this answer which suggests that it is possible and that DocScape implements it. Since the players are way above my head and not chiming in here (yet), I will assume it is non-trivial. – StrongBad Apr 07 '13 at 11:33
  • 1
    @DanielE.Shub Yep, correct. DocScape does this with TeX behind, in the manner David suggests: When a paragraph breaks "off" from one page to the next, it will be re-typeset with a parshape to reflect the new width. Note however that DocScape has a page model which is at the same time richer and poorer than that of LaTeX. For instance, in DocScape, paragraphs like to go in a fixed place on the page immediately after being typeset. – Stephan Lehmke Apr 07 '13 at 13:30
  • If you're willing to set all page breaks manually, this can be done with \newgeometry and \restoregeometry. But I suspect you want something automatic? – Tom Bombadil May 21 '13 at 12:29
  • yep... a manual solution isn't going to be a problem, and can even be done out of the box, without geometry or anything. – Nils L May 21 '13 at 12:34
  • I tried to automate it with background and everyshi, without luck (only errors). everypage almost does the trick, but there only one margin is changed, thus printing over the page border. – Tom Bombadil May 21 '13 at 12:45

1 Answers1

13

This only works for simple cases, but could be extended and generalised a bit.

enter image description here

\documentclass{article}
\makeatletter

\def\a{Cat dog goat sheep pig rabbit cow kangeroo. }
\def\b{One two three four five six. }
\def\c{\a\a\b\a\b\b\a\a\a\a\b\b\a\b}
\def\d{\c\par\a\b\c\par\b\b\b\b\b\b\par}
\def\e{\par\d\d\b\b\b\b\b\d\a\a\a\a\a\a\a\d}


\def\shp#1{%
\@tempcnta\z@
\loop
\advance\@tempcnta\@ne
\edef\pshape{\pshape 0pt #1 }
\ifnum\@tempcnta<46
\repeat
\advance\@tempcntb46
}
\begin{document}

{
\@tempcntb\z@
\def\pshape{}
\shp{5in}\shp{3in}
\shp{5in}\shp{3in}
\shp{5in}\shp{3in}
\def\par{\ifhmode\\\fi\hspace*{\parindent}\ignorespaces}
\show\pshape
\parshape\@tempcntb\pshape
\e\e
\endgraf
}

\end{document}
David Carlisle
  • 757,742
  • It seems like the number of pages and lines per page are hardwired. Is this correct? Could you use something like the lastpage package to automate the number of pages and the lineno package to get the lines per page? – StrongBad May 24 '13 at 08:07
  • @DanielE.Shub lines per page is hardwired to 46 that could be set in the preamble by dividing \textheight by \baselineskip as written it only allows 6 pages before you have to have a real paragraph break and new page then start again. You could add as many \shp commands as you need but depending on the page size you can not have more than 20 or so as otherwise you will exceed the capacity of TeX's paragraph builder. Really each paragraph should be set as a new TeX primitive paragraph with a parshape depending on the position on the current page, but that can be hard to do – David Carlisle May 24 '13 at 08:13
  • Small suggestion: If you load the lipsum package, you could change your \e\e to \lipsum[1-26]. – John Wickerson May 24 '13 at 08:43
  • @JohnWickerson I'm having a one man crusade against the lipsum package:-) – David Carlisle May 24 '13 at 08:44
  • Lorem ipsum.... – Nicholas Hamilton May 27 '13 at 06:47
  • @DavidCarlisle What I find interesting is the contrast between (a) Frank's saying that it may not be solvable at all, as well as other people saying it's extremely complicated and (b) your rather straightforward (if limited) solution. I'd love to hear Frank's ideas as well (someday, probably not within the bounty deadline). – Nils L May 27 '13 at 07:39
  • as for the limitations: I've tried to find out if your solution accepts any \sectioning, but whereever I put my \section commands, it didn't go too well. What do you think it would take to make your code compatible with them? – Nils L May 27 '13 at 07:47
  • @NilsL this sets everything as one paragraph with a parshape designed to fit the page breaks so you either need to design a sectioning command that similarly uses forced linebreaks rather than a new paragraph (not too hard probably) or you have to do a more complete job that allowed multilple pararaphs and at the start of each mone measured where you are and set up a new parshape to fit the rest of the current page, that's a lot harder and harder still if you allow latex floats to float in and change the space left on the page. To do a really proper job you would have to rewrite half of latex – David Carlisle May 27 '13 at 13:11
  • @DavidCarlisle seeing your answer makes me think it is not that hard. The lineno package will let you know how many lines are on each page and let you label the first/last line of every paragraph. This should be all the info you need to set the parshape. This of course depends on lineno working with parshape. – StrongBad May 27 '13 at 14:08
  • @DanielE.Shub @DavidCarlisle okay, I'm beginning to understand what your code actually does and why (and to understand that \parshape is good for more than gimmicks). I still think this issue might deserve even more attention, but I'd say it's definitely a solution as defined by Daniel, and one I like a lot, particularly because it's so instructive regarding TeX's paragraph algorithms :) – Nils L May 27 '13 at 18:56