Abbildungsinhalte werden nach Änderungen an der Ausgaberoutine nicht auf geraden Seiten angezeigt

Abbildungsinhalte werden nach Änderungen an der Ausgaberoutine nicht auf geraden Seiten angezeigt

In einem Dokument mit breiten Rändern möchte ich eine Abbildungsumgebung anbieten, die sich bis in den Randbereich erstreckt. Außerdem möchte ich, dass der Beschriftungstext ebenfalls in diesem Bereich platziert wird, entweder über oder unter der Abbildung, je nach Platzierung der Abbildung. Außerdem sollte dies auf geraden und ungeraden Seiten funktionieren ( scrbookin meinem Fall verwende ich , aber die twosideOption hätte auch den gleichen Effekt).

Was ich letztendlich erreichen möchte, lässt sich vielleicht am besten anhand der folgenden Abbildungen veranschaulichen (sehr schnelle Zeichnungen in Inkscape, die unterschiedlichen Größen sind mir egal):

Bildbeschreibung hier eingebenBildbeschreibung hier eingebenBildbeschreibung hier eingeben

Zunächst möchte ich die Referenzen von \cite-Makros sammeln und sie unten im Rand ausgeben (das funktioniert und wird daher im MWE nicht angezeigt). Eine breite Abbildung sollte ihre Beschriftung auch im Rand haben. Wenn eine breite Abbildung unten vorkommt, möchte ich, dass die Referenzen über der Beschriftung der Abbildung im Rand stehen. Es kann vorkommen, dass etwas auch im oberen Rand ausgegeben wird. Wie Sie an den Abbildungen sehen, sollte es im twosideModus funktionieren.

Um zu erkennen, wo eine Figur platziert ist, verwende ich Code vorgeschlagen von David CarlisleUm die Überschrift am Seitenrand zu positionieren, entweder am unteren oder am oberen Rand einer Seite, verwende ichCode vorgeschlagen von Heiko Oberdiek. Um zu testen, ob die aktuelle Seite gerade oder ungerade ist, verwende ich bei Verwendung \ifthispageoddvon from KOMA-Scriptund um sicherzustellen, dass die Abbildung bis in den äußeren Rand reicht, verwende ich die addmargin*Umgebung von KOMA-Script.

widefigureAbgesehen von einigen Warnungen, auf die ich später eingehen werde, funktioniert der Ansatz auf ungeraden Seiten wie erwartet, auf geraden Seiten erscheint der Inhalt meiner neuen -Umgebung jedoch nicht, obwohl im entsprechenden Bereich noch Platz vorhanden ist.

Das Problem besteht darin, dass die beiden oben genannten Codeteile (irgendwie) mit der Ausgaberoutine (dem WortÄnderungenim Titel ist möglicherweise nicht ganz korrekt), was für mich eine Blackbox ist. Ich habe nur geringfügige Änderungen am Code vorgenommen (Davids \floatswitchin \@floatswitch, \fooin umbenannt \@helperund die Längenargumente des \putMakros geändert, das Heiko zum Positionieren der Notizen am Rand verwendet hat).

Kann mir jemand erklären, warum die Abbildungsinhalte nicht auf geraden Seiten erscheinen (oder, noch besser, dafür sorgen, dass sie erscheinen)?

Das MWE ist aufgrund der oben erwähnten Codeausschnitte lang. Ich habe versucht, einige Kommentare (in meinen Code) einzufügen, die zum Verständnis des Ansatzes beitragen. Heikos Code war ebenfalls kommentiert.

\documentclass[paper=a4,11pt]{scrbook}

\usepackage[left=1in,top=1in,headsep=2\baselineskip,
  textwidth=26pc,marginparsep=2pc,marginparwidth=12pc,
  textheight=44\baselineskip,headheight=\baselineskip]{geometry}

% It took me a while to figure out the (x)color here is not merely used for
% providing color...

\usepackage{xcolor,atbegshi,picture,zref-abspage}
\usepackage{lipsum}
\makeatletter
%\input{../features/widefigures.tex}

% This magic has been posted by David Carlisle on TeX-SX:
% https://tex.stackexchange.com/questions/56017/formatting-floats-differently-based-on-placement

\def\@floatswitch#1#2#3#4{%
  \def\@elt##1{\global\value{##1}\the\value{##1}\relax}%
  \edef\FS@ckpt{\cl@@ckpt}%
  \let\@elt\relax
\hbox to 3sp{%
\vbox{{\FS@ckpt#1\par}}%
\vbox{{\FS@ckpt#2\par}}%
\vbox{{\FS@ckpt#3\par}}%
\vbox{{\FS@ckpt#4\par}}%
\hss}\aftergroup\break}

\def\FS@checkswitch#1{%
\ifdim\wd#1=3sp %
\setbox\z@\box#1%
\begingroup
\vbadness\maxdimen
\setbox\z@\vsplit\z@ to \textheight
\setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}%
\setbox\z@\vbox{\unvbox\@ne\unskip\global\setbox\@ne\lastbox}
\setbox\z@\hbox{\unhbox\@ne\unskip
\FS@junk
\global\setbox\@ne\lastbox}%
\endgroup
\else
\global\setbox\@ne\box#1%
\fi}

\def\@comflelt#1{%
\FS@checkswitch#1%
\setbox\@tempboxa
      \vbox{\unvbox\@tempboxa\box\@ne\vskip\floatsep}}

\let\saved@cflt\@cflt
\def\@cflt{%
\def\FS@junk{\setbox\z@\lastbox\setbox\z@\lastbox\setbox\z@\lastbox}%
\saved@cflt}

\let\FS@junk\relax
\let\saved@cflb\@cflb
\def\@cflb{%
\def\FS@junk{\setbox\z@\lastbox\setbox\z@\lastbox}%
\saved@cflb}


\def\@helper#1\box\@currbox#2!!{%
\def\@addtocurcol{%
#1%
\let\FS@junk\relax
\FS@checkswitch\@currbox
\box\@ne
#2}}%
\expandafter\@helper\@addtocurcol!!

\def\@wtryfc #1{%
  \global\setbox\@outputbox\vbox{%
    \unvbox\@outputbox
    \vskip\@fpsep
\def\FS@junk{\setbox\z@\lastbox}%
\FS@checkswitch#1%
\box\@ne}}

%
% Provide a macro that allows typesetting into the margin 
%

\newcommand\@wide[2]{%#1%
  \begin{addmargin*}[0cm]{#1}#2\end{addmargin*}%
}

%
% An environment to deal with figure-like content
%

\newsavebox{\@ContentCollectorBox}
\newenvironment{@CollectContentAndCaption}[1][\linewidth]{%
  % This environment collects its content in the box \@ContentCollectorBox,
  % the width of the box is given by the optional argument #1 (defaults to
  % \linewidth) 
  % Furthermore, it redefines the \caption macro and saves its content in the
  % macros \@CurrCaptionLong and \@CurrCaptionShort. 
  %
  % The box and the two macros are available globally.
  \begingroup
    \begin{lrbox}{0\null\global\setbox\@ContentCollectorBox}%
      \begin{minipage}{#1}
        \renewcommand\caption[2][]{%
           \gdef\@CurrCaptionLong{##2}%
           \ifx\\##1\\
             \gdef\@CurrCaptionShort{##2}%
           \else
             \gdef\@CurrCaptionShort{##1}%
           \fi
        }%
}{%
      \end{minipage}
    \end{lrbox}
  \endgroup
}

%
% An environment providing a floating figure which extends in the margin.
%

\newenvironment{widefigure}[1][]{%
  % Store the optional argument. If provided, add square brackets around.
  \ifx\\#1\\
    \def\@rgOne{}%
  \else
    \def\@rgOne{[#1]}%
  \fi
  %
  % Start the environment defined above
  \begin{@CollectContentAndCaption}[\dimexpr\textwidth+\marginparsep+\marginparwidth]%
}{%
  % End the environment 
  \end{@CollectContentAndCaption}%
  % Start the figure-environment with the optional argument from
  % the \begin{widefigure} part. I use \figure here to avoid an
  % \expandafter-orgy to expand the argument
  \expandafter\figure\@rgOne
  % \@floatswitch is a command from within the magic, I just added the @ 
    \@floatswitch{%
      % If you comment the \topmarginpar-commands here, the figure content
      % will appear at the desired position.
      %
      % Output the caption. 
      \topmarginpar{\@CurrCaptionLong}%
      % add a rule to the topmargin-collection with a width of zero and the
      % height+depth of the box containing the content without the caption
      % from the environment used  above.
      \topmarginpar{\rule{0pt}{%
          \dimexpr\ht\@ContentCollectorBox+\dp\@ContentCollectorBox}}%
      %
      %
      % use the content of the widefigure-environment.
      %%%
      %%% This does not appear on even pages
      %%%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      % Same as above. If you comment the \botmarginpar-commands here, the
      % figure content  will appear at the desired position.
      %
      \botmarginpar{\@CurrCaptionLong}%
      \botmarginpar{\rule{0pt}{%
          \dimexpr\ht\@ContentCollectorBox+\dp\@ContentCollectorBox}}%
      % The bottom-content appears only on odd pages
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }
  \endfigure
}

%
% This magic has been posted by Heiko Oberdiek
%  https://tex.stackexchange.com/questions/69517/send-and-stack-marginpar-to-the-top-or-the-bottom-of-the-page


\providecommand*{\c@zabspage}{\c@abspage}
% * User macros for configuring
%
% \tbmparItemSep is inserted between marginal notes
% \tbmparMiddleSep is inserted between top and bottom marginal notes.

\newcommand*{\tbmparItemSep}{%
  \vspace{1ex minus .5ex}%
  \hrule
  \vspace{1ex minus .5ex}%
}
\newcommand*{\tbmparMiddleSep}{%
  \vspace*{0pt plus 1fil}%
}
% * Debug messages
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Label management to remember absolute page number
%
% \tbmpar@PageByLabel stores and loads absolute page number from
% label and defines \tbmpar@page with absolute page number or
% zero if the label is not yet available.

\newcount\c@tbmpar@item
\c@tbmpar@item\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@page{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0}%
  }%
  \zref@refused{tbmpar\the\c@tbmpar@item}%
  \tbmparDebug{Item \the\c@tbmpar@item\space on page \tbmpar@page}%
}

% * Box register management

\newcount\c@tbmpar@box
\c@tbmpar@box\z@

\let\tbmpar@boxfreelist\@empty

% Get a new free box register either from the free list or,
% if the free list is empty, allocate a new box register.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@next#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Reused box: #1}%
  }{%
    \global\advance\c@tbmpar@box\@ne
    \expandafter\newbox\csname tbmpar@box\the\c@tbmpar@box\endcsname
    \edef#1{\csname tbmpar@box\the\c@tbmpar@box\endcsname}%
    \tbmparDebug{New box: #1}%
  }%
}
% Put free box in free list.
\newcommand*{\tbmpar@FreeBox}[1]{%
  \begingroup
    \let\@elt\relax
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Free box: #1}%
  \endgroup
}

\newsavebox{\tbmpar@box}

% Each marginpar is put in a box that is initialized as
% parbox/minipage.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{% 
  \vbox{%
    \color@begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \if@minipage
        \noexpand\@minipagetrue
      \else
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@marginparreset
    \tbmparBoxSetup 
    #1%
    \tbmpar@restore@ifminipage
    \color@endgroup
  }%
}   

% Macro \tbmpar@marginpar looks for the page, where the margin note
% belongs to, stores the note in a box and appends the box to the  
% note collector register of the page.
% Each page is assigned a box collector registers that collect
% the top notes and a register that collect the bottom notes. 
% The name of the box register is \tbmpar@<top|bot>box<page>. 
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmode
    \@bsphack
  \fi
  \tbmpar@PageByLabel
  \ifnum\tbmpar@page>\z@
    \setbox\tbmpar@box\tbmpar@VBox{#4}%
    \@ifundefined{tbmpar@#1box\tbmpar@page}{%
      \tbmpar@NextBox\tbmpar@currbox
      \global\expandafter\let
          \csname tbmpar@#1box\tbmpar@page\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@box
      }%
    }{% 
      \tbmparDebug{Use box: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@page\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#3%
        \par
        \begingroup
          \tbmparItemSep
        \endgroup
        \unvbox#2%
      }%
    }%  
  \fi   
  \ifhmode
    \@esphack
  \fi
}

\newcommand*{\topmarginpar}{%
  \tbmpar@marginpar{top}\tbmpar@currbox\tbmpar@box
}
\newcommand*{\botmarginpar}{%
  \tbmpar@marginpar{bot}\tbmpar@box\tbmpar@currbox
}

% At shipout time we look for the box collector registers of this
% page and set these boxes in the marginpar box with respecting  
% \topskip and \maxdepth.
\def\@marginparxpos{0pt}\def\@marginparypos{0pt}%
\AtBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    %
    % I added the following definition of the corresponding lengths to be able
    % to distinguish odd and even pages. 
    %
    \ifthispageodd{%
      \def\@marginparxpos{\dimexpr
        1in+\oddsidemargin+\textwidth+\marginparsep\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}% 
    }{%
      \def\@marginparxpos{\dimexpr
        1in+\evensidemargin-\marginparsep-\marginparwidth\relax}%
      \def\@marginparypos{-\dimexpr
        1in+\topmargin+\headheight+\headsep+\textheight\relax}% 
    }
    \put(%
      \@marginparxpos,\@marginparypos%
    ){%
      \begingroup
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \penalty-\@M
          \edef\tbmpar@tmp{tbmpar@topbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          \endgraf
          \tbmparMiddleSep
          \edef\tbmpar@tmp{tbmpar@botbox\the\value{zabspage}}%
          \@ifundefined{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@box to\z@
          \boxmaxdepth=\maxdepth
          \setbox\tbmpar@box=\vbox to\textheight{%
            \unvbox\tbmpar@box
          }%
          \box\tbmpar@box
        \fi
      \endgroup
    }%
  }%  
}     

\makeatother
\begin{document}
%
% If you comment the next line, there is an additional error. If someone could
% solve this, help is appreciated. But currently that's not the main issue.
\topmarginpar{}
 \begin{widefigure}[t]
   \color{green}\rule{\linewidth}{2cm}
   \caption{Top placement of figure, odd page.} 
 \end{widefigure}
\botmarginpar{Bottom margin note seems to be fine.}
\lipsum[2-5]
% Now we are on an even page
\topmarginpar{\lipsum[57]}
\botmarginpar{\lipsum[57]}
\lipsum[1-6]
% On an odd page, again
\begin{widefigure}[b]
  \color{green}\rule{\linewidth}{2cm}
  \caption{Bottom placement, odd page}
\end{widefigure}
\lipsum[1-3]
% Now we are on an even page!
\begin{widefigure}[t]
  \color{red}\rule{\linewidth}{2cm}
  \caption[A normal caption]{Top placement, even page. Figure vanished!}
\end{widefigure}
\lipsum
\begin{widefigure}[b]
  \color{red}\rule{\linewidth}{2cm}
  \caption[A normal caption]{Bottom placement, even page. Figure vanished!}
\end{widefigure}
\lipsum[1-12]
\end{document}

Antwort1

Ich habe die Lösung geändert, um die Bildunterschriften einzuschließen. Das Makro \gettruepage gibt jetzt auch die x- und y-Position zurück (um zu prüfen, ob oben oder unten ist). Beachten Sie, dass es zwei Durchläufe braucht, damit es richtig funktioniert, da es die AUX-Datei verwendet.

\documentclass[paper=a4,11pt]{scrbook}

\usepackage[left=1in,top=1in,headsep=2\baselineskip,
  textwidth=26pc,marginparsep=2pc,marginparwidth=12pc,
  textheight=44\baselineskip,headheight=\baselineskip]{geometry}

% It took me a while to figure out the (x)color here is not merely used for
% providing color...

\usepackage{xcolor}
\usepackage{lipsum}
\usepackage{environ}% create an environment using \BODY

% The \gettruepage marcro returns the page number (as \truepage} in places where \thepage won't,
% such as inside floats or paragraphs split over 2 pages.

\pdfpageheight=\paperheight
\pdfpagewidth=\paperwidth

\newcounter{truepageindex}
\newcount{\truepage}% returns page
\newlength{\truex}% returns distance from left side of text area
\newlength{\truey}% returns distance from top of text area

\newcommand{\newtruepage}[4]% #1 = \thetruepageindex, #2 = \thepage, #3 = \pdflastxpos, #4 = \pdflastypos
{\global\expandafter\edef\csname truepage#1\endcsname{#2}%
 \global\expandafter\edef\csname truex#1\endcsname{#3}%
 \global\expandafter\edef\csname truey#1\endcsname{#4}}

\makeatletter
\newcommand{\gettruepage}{\stepcounter{truepageindex}%
  \pdfsavepos
  \protected@write\@auxout{}{\string\newtruepage{\thetruepageindex}{\thepage}
    {\noexpand\number\pdflastxpos}{\noexpand\number\pdflastypos}}%
  \@ifundefined{truepage\thetruepageindex}%
   {\truepage=\c@page \truex=0pt \truey=0pt}%
   {\truepage=\csname truepage\thetruepageindex\endcsname\relax
    \truex=\csname truex\thetruepageindex\endcsname sp\relax
    \truey=\csname truey\thetruepageindex\endcsname sp\relax
    \truey=\dimexpr \paperheight-\truey-1in-\topmargin-\headheight-\headsep\relax
    \advance\truex by -1in
    \ifodd\truepage\relax\advance\truex by -\oddsidemargin
    \else \advance\truex by -\evensidemargin
    \fi}%
}%
\makeatother

% caption handler
\newif{\iffakecaption}
\newcommand{\fakecaptiontext}{}% reserve name
\makeatletter
\newcommand{\fakecaption}[2][\@empty]% #1 = short caption (optional), #2 = long caption
 {\global\fakecaptiontrue
  \refstepcounter{figure}%
  \ifx#1\@empty\def\fakecaptiontext{#2}%
  \else\def\fakecaptiontext{#1}%
  \fi
  \addcontentsline{lof}{figure}{\string\numberline {\thefigure}{\ignorespaces \fakecaptiontext}}%
  \gdef\fakecaptiontext{#2}}
\makeatother

% widefigure environment

\newsavebox{\widefigurebox}
\newsavebox{\widefigurecaption}
\newlength{\widefiguretest}% compares middle of figure to middle of text area
\newlength{\widefigureup}% baseline to baseline for caption above
\newlength{\widefiguredown}% baseline to baseline for caption below
\newlength{\widefiguresize}% total height of figure plus caption plus extra \marginparpush
\newcount{\widefigurelast}% last page with figure on bottom

\NewEnviron{widefigure}[1][\empty]{%
\figure[#1]%
\let\oldcaption=\caption
\let\caption=\fakecaption
\fakecaptionfalse
\savebox{\widefigurebox}{\begin{minipage}{\dimexpr \textwidth+\marginparsep+\marginparwidth}%
\BODY\end{minipage}}%
\let\caption=\oldcaption
\settoheight{\widefigureup}{\usebox{\widefigurebox}}%
\settodepth{\widefiguredown}{\usebox{\widefigurebox}}%
\widefiguretest=\dimexpr .5\textheight-.5\widefigureup +.5\widefiguredown\relax
\advance\widefigureup by \marginparpush
\iffakecaption
  \savebox{\widefigurecaption}{\parbox{\marginparwidth}%
    {\raggedright\textbf{Figure \thefigure: }\fakecaptiontext}}%
    \settodepth{\widefiguresize}{\usebox{\widefigurecaption}}%
    \advance\widefigureup by \widefiguresize
  \settoheight{\widefiguresize}{\usebox{\widefigurecaption}}%
    \advance\widefiguredown by \widefiguresize
  \advance\widefiguredown by \marginparpush
\fi
\gettruepage
\leavevmode% needed for \rlap and \llap
\ifodd\truepage\relax
  \rlap{\usebox{\widefigurebox}}%
  \iffakecaption
      \ifdim\truey>\widefiguretest\relax
      \rlap{\hspace{\textwidth}\hspace{\marginparsep}%
        \raisebox{\widefigureup}[0pt][0pt]{\usebox{\widefigurecaption}}}%
      \global\widefigurelast=\truepage
    \else
      \rlap{\hspace{\textwidth}\hspace{\marginparsep}%
        \raisebox{-\widefiguredown}[0pt][0pt]{\usebox{\widefigurecaption}}}%
    \fi
  \fi
\else
  \rlap{\hspace{-\marginparwidth}\hspace{-\marginparsep}\usebox{\widefigurebox}}%
  \iffakecaption
      \ifdim\truey>\widefiguretest\relax
      \llap{\raisebox{\widefigureup}[0pt][0pt]{\usebox{\widefigurecaption}}%
        \hspace{\marginparsep}}%
      \global\widefigurelast=\truepage
    \else
      \llap{\raisebox{-\widefiguredown}[0pt][0pt]{\usebox{\widefigurecaption}}%
        \hspace{\marginparsep}}%
    \fi
  \fi
\fi
\advance\widefigureup by \widefiguredown
\global\widefiguresize=\widefigureup
\endfigure}

\begin{document}
%
% If you comment the next line, there is an additional error. If someone could
% solve this, help is appreciated. But currently that's not the main issue.
%\topmarginpar{}
\begin{widefigure}[t]
   \color{green}\rule{\linewidth}{2cm}%  percent needed to prevent blank line at botttom
   \caption{Top placement of figure, odd page.}\label{test}
\end{widefigure}
This is a label test for Figure \ref{test}.
The height of the figure plus caption is \the\widefiguresize.

\lipsum[2-5]
% Now we are on an even page
\lipsum[1-6]
% On an odd page, again
\begin{widefigure}[b]
  \color{green}\rule{\linewidth}{2cm}%
  \caption{Bottom placement, odd page}
\end{widefigure}
\lipsum[1-3]
% Now we are on an even page!
\begin{widefigure}[t]
  \color{red}\rule{\linewidth}{2cm}%
  \caption[A normal caption]{Top placement, even page. Figure vanished!}
\end{widefigure}
\lipsum
\begin{widefigure}[b]
  \color{red}\rule{\linewidth}{2cm}%
  \caption[A normal caption]{Bottom placement, even page. Figure vanished!}
\end{widefigure}
\lipsum[1-3]
\listoffigures
\end{document}

Antwort2

Ich habe etwas gefunden, das eine Lösung zu sein scheint. Obwohl es noch nicht vollständig ist und einige Kästchen nicht ausgefüllt sind, macht es mehr oder weniger das, was ich will. Der Abstand scheint auch nicht zu stimmen.

Das Ziel dieser Lösung war, dass mir (nachdem ich eine ganze Weile versucht hatte, Davids Code zu verstehen) klar wurde, dass \@cfltund \@cflbje nach Positionierung des Floats erweitert werden. David verwendet dies, um verschiedene Versionen von zu definieren, \FS@junkdie die nicht benötigten Boxen wegwirft, und ich verwende es, um eine Länge festzulegen, die \vspace*entweder oben oder unten an der Box liegt, die den Inhalt des Rands enthält.

Dies funktioniert, solange zwei Floats auf derselben Seite erscheinen, da ich nur eine Länge verwende, um die vertikale Dimension des Floats zu speichern, die einfach durch den zweiten Float überschrieben wird. Eine Lösung könnte hier sein, den entsprechenden Zähler (Abbildung/Tabelle) zu verwenden oder einen neuen einzuführen.

Darüber hinaus verwende ich keinen auf Label-Red basierenden Mechanismus mehr zur Erkennung, ob die Seite gerade oder ungerade ist, was zu keinen Beschwerden über undefinierte Labels führt (Herberts Code benötigt Labels und damit zwei Durchläufe, aber beim zweiten Durchlauf gibt es keine Warnungen).

Hier ist das MWE (wieder lang, beide oben verlinkten Code-Schnipsel sind enthalten). Ich habe Davids Code (soweit ich ihn verstehe) mit einigen Kommentaren versehen, vielleicht hilft das anderen, ihn besser zu verstehen.

\documentclass[Papier=a4,11pt]{Scrbook}
\usepackage[T1]{Schriftart}
\usepackage[links=1in,oben=1in,headsep=2\baselineskip,
  Textbreite = 26 Stk., Randparsep = 2 Stk., Randparbreite = 12 Stk.,
  Texthöhe = 44 \ baselineskip, Kopfhöhe = \ baselineskip] {Geometrie}

\usepackage{xcolor,atbegshi,picture,zref-abspage,ragged2e}
\usepackage{lipsum}
\einen Brief machen

% Dieser Zauber wurde von David Carlisle auf TeX-SX gepostet:
% http://tex.stackexchange.com/questions/56017/formatting-floats-differently-based-on-placement


%
% Das \@floatswitch-Makro erwartet 4 Argumente, nämlich den Inhalt des Floats
%, die gesetzt werden sollen, wenn sie oben (#1), unten (#2), auf einer einzelnen
% Seite (#3) oder hier (#4)
%

\def\@floatswitch#1#2#3#4{%
  % (Schätzung) Diese Zeilen befassen sich irgendwie mit den Zählern, um zu verhindern, dass die
  %-Zähler werden um mehr als eins erhöht.
  \def\@elt##1{\global\value{##1}\der\value{##1}\relax}%
  \edef\FS@ckpt{\cl@@ckpt}%
  \let\@elt\relax
  % Das Gegenhandeln endet hier, wird aber von \FS@ckpt verwendet
  \hbox bis 3sp{%
    \vbox{{\FS@ckpt#1\par}}%
    \vbox{{\FS@ckpt#2\par}}%
    \vbox{{\FS@ckpt#3\par}}%
    \vbox{{\FS@ckpt#4\par}}%
    \hss}\nachgruppe\break%
}

%
% Hier ist das richtige Kästchen ausgewählt. Das Makro, das dies erledigt, ist \FS@junk,
%, wodurch die Kartons, die nicht verwendet werden, weggeworfen werden.
%
\def\FS@checkswitch#1{%#
  \ifdim\wd#1=3sp %
    \setbox\z@\box#1%
    \Beginngruppe
      \vschlechtheit\maxdimen
      \setbox\z@\vsplit\z@ auf \textheight
      \setbox\z@\vbox{\unvbox\z@\global\setbox\@ne\lastbox}%
      \setbox\z@\vbox{\unvbox\@ne\unskip\global\setbox\@ne\lastbox}%
      \setbox\z@\hbox{\unhbox\@ne\unskip
        \FS@junk
        \global\setbox\@ne\lastbox}%
    \Ende der Gruppe
  \anders
    \global\setbox\@ne\box#1%
  \fi}


% Ich habe keine Ahnung von dem folgenden Makro

\def\@comflelt#1{%
  \FS@checkswitch#1%
  \setbox\@tempboxa
     \vbox{\unvbox\@tempboxa\box\@ne\vskip\floatsep}}

% Offensichtlich (nun, es ist nur eine fundierte Vermutung) wird \@cflt verwendet, wenn ein Float
% steht oben auf der Seite. Als ich das erkannte, war mein Problem
% fast gelöst.

\let\gespeichert@cflt\@cflt

\def\@cflt{%
  \def\FS@junk{%
    % Da der Float oben auf der Seite positioniert ist, erhöhen wir den
    % \tmbparTopSepLength um etwas Platz am oberen Rand der Box zu erhalten
    % enthält den Inhalt des Randes
    \setlength{\tbmparTopSepLength}{\baselineskip}%
    \addtolength{\tbmparTopSepLength}{\captionlength}%
    \addtolength{\tbmparTopSepLength}{\contentlength}%
    \global\tbmparTopSepLength=\tbmparTopSepLength
    \setbox\z@\lastbox\setbox\z@\lastbox\setbox\z@\lastbox}%
  \gespeichert@cflt}

\let\FS@junk\relax

% Dies ist (eine weitere Vermutung) der Befehl, der erweitert wird, wenn ein Float
% am unteren Seitenrand. Die verwendete Methode ist die gleiche wie oben.
\let\gespeichert@cflb\@cflb

\def\@cflb{%
  \def\FS@junk{%
    \setlength{\tbmparBottomSepLength}{2\baselineskip}%
    \addtolength{\tbmparBottomSepLength}{\captionlength}%
    \addtolength{\tbmparBottomSepLength}{\contentlength}%
    \global\tbmparBottomSepLength=\tbmparBottomSepLength
    \setbox\z@\lastbox\setbox\z@\lastbox}%
  \gespeichert@cflb}

% Auch hier keine Ahnung.

\def\@helper#1\box\@currbox#2!!{%
  \def\@addtocurcol{%
    #1%
    \let\FS@junk\relax
    \FS@Checkswitch\@currbox
    \box\@ne
    #2}}%

\expandafter\@helper\@addtocurcol!!

% Und wieder keine Ahnung.

\def\@wtryfc #1{%
  \global\setbox\@outputbox\vbox{%
    \unvbox\@Ausgabebox
    \vskip\@fpsep
  \def\FS@junk{\setbox\z@\lastbox}%
  \FS@checkswitch#1%
  \box\@ne}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



%
% Eine Umgebung für den Umgang mit figurähnlichen Inhalten
%
\newsavebox{\@ContentCollectorBox}
\newsavebox{\@CaptionCollectorBox}
\newenvironment{@CollectContentAndCaption}[1][\linewidth]{%
  % Diese Umgebung sammelt ihren Inhalt in der Box \@ContentCollectorBox,
  % Die Breite der Box wird durch das optionale Argument #1 angegeben (standardmäßig
  % \Linienbreite)
  % Außerdem wird das \caption-Makro neu definiert und dessen Inhalt im
  % Makros \@CurrCaptionLong und \@CurrCaptionShort.
  %
  % Die Box und die beiden Makros sind global verfügbar.
  \Beginngruppe
    \begin{lrbox}{0\null\global\setbox\@ContentCollectorBox}%
      \begin{minipage}{#1}%
        \erneuernBefehl\caption[2][]{%
           \gdef\@CurrCaptionLong{##2}%
           \ifx\\##1\\
             \gdef\@CurrCaptionShort{##2}%
           \anders
             \gdef\@CurrCaptionShort{##1}%
           \fi
        }%
}{%
      \end{minipage}%
    \end{lrbox}%
  \Ende der Gruppe
}

%
% Eine Umgebung, die eine schwebende Figur bereitstellt, die sich bis in den Rand erstreckt.
%
\newenvironment{widefigure}[1][]{%
  % Speichern Sie das optionale Argument. Wenn angegeben, fügen Sie eckige Klammern hinzu.
  \ifx\\#1\\
    \def\@rgOne{}%
  \anders
    \def\@rgOne{[#1]}%
  \fi
  %
  % Starten Sie die oben definierte Umgebung
  \begin{@CollectContentAndCaption}[\dimexpr\textwidth+\marginparsep+\marginparwidth]%
}{%
  % Beenden Sie die Umwelt
  \end{@CollectContentAndCaption}%
  \begin{lrbox}{\@CaptionCollectorBox}%
    \begin{minipage}{\marginparwidth}%
      \UngleichmäßigRechts
      \@CurrCaptionLong
    \end{minipage}
  \end{lrbox}
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % Dies ist Teil der Lösung (und schafft neue Probleme)
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % Hier habe ich global zwei Längen festgelegt, die die vertikale Dimension des
  % Beschriftung und Inhalt
  \setlength{\captionlength}{\ht\@CaptionCollectorBox}%
  \addtolength{\captionlength}{\dp\@CaptionCollectorBox}%
  \global\captionlength=\captionlength\relax
  \setlength{\contentlength}{\ht\@ContentCollectorBox}%
  \addtolength{\contentlength}{\dp\@ContentCollectorBox}%
  \global\inhaltslänge=\inhaltslänge\relax
  % Starten Sie die Figure-Umgebung mit dem optionalen Argument von
  % der \begin{widefigure}-Teil. Ich verwende hier \figure, um ein
  % \expandafter-orgy um das Argument zu erweitern
  \expandafter\figure\@rgOne
  %
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % Auch das ist neu. Hier treten einige nicht volle Kartons auf, die noch
  % geprüft.
  % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  % \@floatswitch ist ein Befehl aus der Magie, ich habe nur das @ hinzugefügt
    \@Schwimmerschalter{%
      \ifodd\c@Seite%
        \rlap{\usebox{\@ContentCollectorBox}}%
        \vbox auf 0pt{%
          \rlap{%
            \hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vss
        }
      \anders
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
        \vbox auf 0pt{%
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vss
        }%
      \fi
    }{%
      %
      % Mehr oder weniger dasselbe wie oben, aber für die Platzierung unten.
      %
      \ifodd\c@Seite%
        \vbox auf 0pt{%
          \vss
          \rlap{\hspace*{\dimexpr\textwidth+\marginparsep}%
            \usebox{\@CaptionCollectorBox}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\usebox{\@ContentCollectorBox}}%
      \anders
        \vbox auf 0pt{%
          \vss
          \llap{%
            \usebox{\@CaptionCollectorBox}%
            \hspace*{\marginparsep}%
          }%
          \vspace*{\baselineskip}%
        }%
        \rlap{\hspace*{\dimexpr-\marginparwidth-\marginparsep}\usebox{\@ContentCollectorBox}}%
      \fi
    }{%
      % Ich brauche noch etwas für die Seitenplatzierung
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }{%
      % Ich möchte nicht, dass hier Zahlen platziert werden. Jedenfalls brauche ich eine Lösung für
      % Das auch.
% \@wide{\wd\@ContentCollectorBox}{\usebox{\@ContentCollectorBox}}%
    }%
  \Ende der Figur
}


%
% Dieser Zauber wurde gepostet von Heiko Oberdiek
% http://tex.stackexchange.com/questions/69517/send-and-stack-marginpar-to-the-top-or-the-bottom-of-the-page


\providecommand*{\c@zabspage}{\c@abspage}

% Ich definiere vier neue Längen, die verwendet werden, um oben Platz zu lassen und
% Ende eines tbmpar-Knotens

\neueLänge\tbmparTopSepLength
\newlength\tbmparBottomSepLength

% und zwei, die die vertikale Dimension der Felder mit der Überschrift beibehalten
% und Inhalt eines Floats
\neueLänge\Beschriftungslänge
\neueLänge\Inhaltslänge

% Zwei Befehle, die oben und unten in der Box erweitert werden, enthalten
% der Inhalt des Randes
\newcommand*{\tbmparTopSep}{%
  \vspace*{\tbmparTopSepLength}%
}
\newcommand*{\tbmparBottomSep}{%
  \vspace*{\tbmparBottomSepLength}%
}

% Ein Makro zum Zurücksetzen der Längen
\newcommand\restoreSeps{%
  \global\tbmparTopSepLength0pt\relax%\@zp
  \global\tbmparBottomSepLength0pt\relax
}
\restoreSeps

% Die nächsten Zeilen sind wieder Heikos Code

% * Benutzermakros zur Konfiguration
%
% \tbmparItemSep wird zwischen Randnotizen eingefügt
% \tbmparMiddleSep wird zwischen den oberen und unteren Randnotizen eingefügt.

\newcommand*{\tbmparItemSep}{%
  \vspace{1ex minus .5ex}%
  \hrule
  \vspace{1ex minus .5ex}%
}

\newcommand*{\tbmparMiddleSep}{%
  \vspace*{0pt plus 1fil}%
}
% * Debug-Meldungen
%
\newcommand*{\tbmparDebug}[1]{%
  \typeout{[tbmpar] #1}%
}

% * Label-Management zum Merken der absoluten Seitenzahl
%
% \tbmpar@PageByLabel speichert und lädt absolute Seitenzahlen von
% label und definiert \tbmpar@page mit absoluter Seitenzahl oder
% Null, wenn das Etikett noch nicht verfügbar ist.

\neueAnzahl\c@tbmpar@item
\c@tbmpar@Artikel\z@

\newcommand*{\tbmpar@PageByLabel}{%
  \global\advance\c@tbmpar@item\@ne
  \zref@labelbyprops{tbmpar\the\c@tbmpar@item}{abspage}%
  \edef\tbmpar@page{%
    \zref@extractdefault{tbmpar\the\c@tbmpar@item}{abspage}{0} %
  }%
  \zref@abgelehnt{tbmpar\das\c@tbmpar@item}%
  \tbmparDebug{Element \der\c@tbmpar@item\Platz auf Seite \tbmpar@page}%
}

% * Box-Register-Verwaltung

\neuerAnzahl\c@tbmpar@box
\c@tbmpar@box\z@

\let\tbmpar@boxfreelist\@empty

% Holen Sie sich eine neue freie Box registrieren entweder aus der Liste der freien oder,
% Wenn die freie Liste leer ist, weisen Sie ein neues Box-Register zu.
\newcommand*{\tbmpar@NextBox}[1]{%
  \@next#1\tbmpar@boxfreelist{%  
    \tbmparDebug{Wiederverwendete Box: #1}%
  }{%
    \global\advance\c@tbmpar@box\@ne
    \expandafter\newbox\csname tbmpar@box\the\c@tbmpar@box\endcsname
    \edef#1{\csname tbmpar@box\the\c@tbmpar@box\endcsname}%
    \tbmparDebug{Neue Box: #1}%
  }%
}
% Freie Box in Freiliste einfügen.
\neuerBefehl*{\tbmpar@FreeBox}[1]{%
  \Beginngruppe
    \let\@elt\relax
    \xdef\tbmpar@boxfreelist{%
      \tbmpar@boxfreelist
      \@elt#1%
    }%
    \tbmparDebug{Freie Box: #1}%
  \Ende der Gruppe
}

\newsavebox{\tbmpar@box}

% Jeder marginpar wird in eine Box gesetzt, die initialisiert wird als
% Parbox/Miniseite.
\newcommand*{\tbmparBoxSetup}{}
\newcommand{\tbmpar@VBox}[1]{%
  \vbox{%
    \Farbe@Begingroup
    \hsize\marginparwidth
    \edef\tbmpar@restore@ifminipage{%
      \if@minipage
        \noexpand\@minipagetrue
      \anders
        \noexpand\@minipagefalse
      \fi
    }%   
    \@parboxrestore
    \@marginparreset
    \tbmparBoxSetup
   #1%
    \tbmpar@restore@ifminipage
    \Farbe@Endgruppe
  }%
}   

% Makro \tbmpar@marginpar sucht nach der Seite, auf der die Randnotiz
% gehört, speichert die Notiz in einer Box und hängt diese Box an die  
% Beachten Sie das Sammlerregister der Seite.
% Jeder Seite ist ein Feld Sammler Register zugeordnet, die sammeln
% die oberen Noten und ein Register, das die unteren Noten sammelt.
% Der Name des Box-Registers ist \tbmpar@box.
\newcommand{\tbmpar@marginpar}[4]{%
  \ifhmode
    \@bsphack
  \fi
  \tbmpar@PageByLabel
  \ifnum\tbmpar@Seite>\z@
    \setbox\tbmpar@box\tbmpar@VBox{#4}%
    \@ifundefined{tbmpar@#1box\tbmpar@page}{%
      \tbmpar@NextBox\tbmpar@currbox
      \global\expandafter\let
          \csname tbmpar@#1box\tbmpar@page\endcsname
          \tbmpar@currbox
      \global\setbox\tbmpar@currbox=\vbox{%
        \unvbox\tbmpar@box
      }%
    }{%
      \tbmparDebug{Box verwenden: \tbmpar@currbox}%
      \expandafter\let\expandafter\tbmpar@currbox
          \csname tbmpar@#1box\tbmpar@page\endcsname
      \global\setbox\tbmpar@currbox\tbmpar@VBox{%   
        \unvbox#3%
        \Par
        \Beginngruppe
          \tbmparItemSep
        \Ende der Gruppe
        \unvbox#2%
      }%
    }%  
  \fi   
  \ifhmode
    \@esphack
  \fi
}

\newcommand*{\topmarginpar}{%
  \tbmpar@marginpar{top}\tbmpar@currbox\tbmpar@box
}
\newcommand*{\botmarginpar}{%
  \tbmpar@marginpar{bot}\tbmpar@box\tbmpar@currbox
}

% Zum Zeitpunkt des Versands suchen wir nach den Box-Sammler-Registern dieser
% Seite und setzen Sie diese Felder in der marginpar Box mit respekt  
% \topskip und \maxdepth.
\def\@marginparxpos{0pt}\def\@marginparypos{0pt}%
\AtBeginShipout{%
  \AtBeginShipoutUpperLeft{%
    %
    % Ich habe die folgende Definition der entsprechenden Längen hinzugefügt, um
    %, um zwischen geraden und ungeraden Seiten zu unterscheiden.
    %
    \ifodd\c@Seite%
      \def\@marginparxpos{\dimexpr
        1 Zoll + \ Oddsidemargin + \ Textbreite + \ Marginparsep \ Relax} %
      \def\@marginparypos{-\dimexpr
        1 Zoll + \oberer Rand + \Kopfhöhe + \Kopfabstand + \Texthöhe \relax} %
    \anders
      \def\@marginparxpos{\dimexpr
        1in+\evensidemargin-\marginparsep-\marginparwidth\relax}%
      \def\@marginparypos{-\dimexpr
        1 Zoll + \oberer Rand + \Kopfhöhe + \Kopfabstand + \Texthöhe \relax} %
    \fi
    \setzen(%
      \@marginparxpos,\@marginparypos%
    ){%
      \Beginngruppe
        \global\let\tbmpar@inuse=N%
        \setbox\tbmpar@box=\tbmpar@VBox{%
          \Strafe-\@M
          %
          % Hier füge ich oben das Leerzeichen ein
          %
          \tbmparTopSep
          \edef\tbmpar@tmp{tbmpar@topbox\the\value{zabspage}}%
          \@ifundeed{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          \endgraf
          \tbmparMittleresSep
          \edef\tbmpar@tmp{tbmpar@botbox\the\value{zabspage}}%
          \@ifundeed{\tbmpar@tmp}{%
          }{%
            \expandafter\let\expandafter\tbmpar@currbox
                \csname\tbmpar@tmp\endcsname
            \unvbox\tbmpar@currbox
            \tbmpar@FreeBox\tbmpar@currbox
            \global\let\tbmpar@inuse=Y%   
          }%
          %
          % Hier füge ich unten das Leerzeichen ein
          %
          \tbmparBottomSep
        }%  
        \ifx\tbmpar@inuse Y%
          \splittopskip=\topskip
          \setbox0=\vsplit\tbmpar@box zu\z@
          \boxmaxdepth=\maxdepth
          \setbox\tbmpar@box=\vbox bis\textheight{%
            \unvbox\tbmpar@box
          }%
          \box\tbmpar@box
        \fi
      \Ende der Gruppe
    }%
  }%  
  % Am Ende werden die Längen zurückgesetzt.
  \restoreSeps
}     

\anderes machen
\begin{document}
\lipsum[1]
\topmarginpar{Eine längere Kopfnote! Eine längere Kopfnote! Eine längere Kopfnote! Eine längere Kopfnote! Eine längere Kopfnote! }
 \begin{widefigure}[t]
   \color{green}\rule{\linewidth}{2cm}
   \caption{Eine längere Bildunterschrift oben! Eine längere Bildunterschrift oben! Eine längere Bildunterschrift oben! Eine längere Bildunterschrift oben!}
 \end{widefigure}
\botmarginpar{Der untere Rand ist unten.}
\lipsum[2-5]
% Jetzt sind wir auf einer Wellenlänge
\botmarginpar{Eine längere Grundnote! Eine längere Grundnote! Eine längere Grundnote! Eine längere Grundnote!}
\begin{widefigure}[b]
  \color{green}\rule{\linewidth}{2cm}
  \caption{Untere Platzierung mit längerer Beschriftung. Untere Platzierung mit längerer Beschriftung. Untere Platzierung mit längerer Beschriftung. Untere Platzierung mit längerer Beschriftung. Untere Platzierung mit längerer Beschriftung. Untere Platzierung mit längerer Beschriftung. }
\end{widefigure}
\lipsum[1-3]

\begin{widefigure}[t]
  \color{red}\rule{\linewidth}{1cm}
  \caption{Eine obere Überschrift, die zuerst definiert wurde.}
\end{widefigure}
\topmarginpar{Eine Kopfnote mit zu großem Abstand.}
\botmarginpar{Eine untere Note mit gleichem Abstand (in diesem Fall ok).}
\begin{widefigure}[b]
  \color{red}\rule{\linewidth}{2cm}
  \caption{Eine untere Überschrift, die als zweite definiert wird. Diese ist länger als die obere
    eins. Auch der Inhalt ist länger.}
\end{widefigure}
\Lippen
\end{document}

verwandte Informationen