How can I clip an image via a bezier-path?

I have a rectangular image that I can not change.

I'd like to clip the image with a bezier path so I get one that is rectangular at the top and the sides but has a curve at the bottom, preferable without using additional packages.

• No package needed if you clip the image using an image editor in advance. As far as I know, graphicx can only clip images in a rectangular form. Therefore you need additional packages such as PSTricks to clip it in a curved form. – xport Jun 5 '11 at 12:15
• Using an editor in advance is not an option, unfortunatelly. Additional packages are acceptable (thou a solution without them would be preferable). – Richard Durr Jun 5 '11 at 12:17
• Your image in what format? eps, jpeg, png, or pdf? – xport Jun 5 '11 at 12:24
• can be converted during the compile-process. let us assume it is png. – Richard Durr Jun 5 '11 at 13:10
• Herbert's solution that is compiled by xelatex can import png, pdf, jpg, eps. – xport Jun 5 '11 at 13:13

I don't know of a way to clip an image without using additional packages (apart from graphicx, I assume). There is a way of doing it with TikZ, which is probably better than no solution.

This is based on the answers to the question Drawing on an image with TikZ. I've written a macro that takes an image name with the accompanying \includegraphics options and a TikZ path as arguments to either display the image overlaid with a grid and the path, or to use the path to clip the image. The behaviour is toggled using \tikzset{develop clipping path=true} to switch on the grid and the path display, and \tikzset{develop clipping path=false} to perform the actual clipping once the path has been developed.

    \documentclass{article}

\usepackage{tikz}
\usepackage{graphicx}

\newif\ifdeveloppath
\tikzset{/tikz/develop clipping path/.is if=developpath,
/tikz/develop clipping path=true}

\newcommand{\clippicture}[2]{
\begin{tikzpicture}
% Include the image to determine the size and set up the relative coordinate system. Enclose the \includegraphics in \phantom{} once the clipping path has been set up
\ifdeveloppath
\node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics#1};
\else
\node[anchor=south west,inner sep=0] (image) at (0,0) {\phantom{\includegraphics#1}};
\fi
\pgfresetboundingbox
\begin{scope}[x={(image.south east)},y={(image.north west)}]
% Draw grid while developing clipping path
\ifdeveloppath
\draw[help lines,xstep=.1,ystep=.1] (0,0) grid (1,1);
\foreach \x in {0,1,...,9} { \node [anchor=north] at (\x/10,0) {0.\x}; }
\foreach \y in {0,1,...,9} { \node [anchor=east] at (0,\y/10) {0.\y}; }
\draw[red, ultra thick] #2 -- cycle;
\else
% Use the path to clip, include the image
\path[clip] #2 -- cycle;
\node[anchor=south west,inner sep=0pt] {\includegraphics#1};
\fi
\end{scope}
\end{tikzpicture}
}

\begin{document}
Show the image with a grid to help in finding the coordinates for the path.

\clippicture{[width=0.8\textwidth]{some-image}}{(0.5,0.75) -- (0.90,0.75) -- (0.90,0.5) .. controls (0.8,-0.2) and (0.65,0.2) .. (0.5,0.3)}

\tikzset{develop clipping path=false}
Done with developing the path. Do the actual clipping.

\clippicture{[width=0.8\textwidth]{some-image}}{(0.5,0.75) -- (0.90,0.75) -- (0.90,0.5) .. controls (0.8,-0.2) and (0.65,0.2) .. (0.5,0.3)}
\end{document}


run with xelatex, then a pdf image can be clipped

\listfiles
\documentclass{article}
\usepackage{graphicx,pstricks}
\newsavebox\IBox
\begin{document}

\savebox\IBox{\includegraphics{/tmp/two.pdf}}

\begin{pspicture}(\wd\IBox,\ht\IBox)
\psclip{\pscustom[linestyle=none]{%
\psline(0,0.2\ht\IBox)(0,\ht\IBox)(\wd\IBox,\ht\IBox)(\wd\IBox,0.3\ht\IBox)
\psbezier(0.75\wd\IBox,0)(0.25\wd\IBox,0.5\ht\IBox)(0,0.2\ht\IBox)}}
\rput[lb](0,0){\usebox\IBox}
\endpsclip
\end{pspicture}

\end{document}


• It is a compact solution with a nice photograph. – xport Jun 5 '11 at 13:09
• You can use \pst@boxg as a temporary box. – xport Jun 22 '11 at 7:39
• @xport: I know, but it requires makeatletter ....\makeatother and it is defined for internal use of PSTricks – user2478 Jun 22 '11 at 7:45

I take some ideas from Drawing on an image with Tikz but with another method and I complete the code with Jack's method for the clip image.

\documentclass{scrartcl}
\usepackage{tikz,fullpage}
\usetikzlibrary{fit,calc,spy}

\tikzset{number/.style={fixed,fixed zerofill,precision=1}}
\makeatletter
\tikzset{spy style/.style={spy using outlines={magnification=8, size=4cm}}}
\newenvironment{IncludeGH}[2][\textwidth]{%
\def\GHClipImage{#2}
\begin{scope}[spy style]
\node[anchor=south west,inner sep=0](GHimage){\includegraphics[width=#1]{#2}};
\begin{scope}[x={(GHimage.south east)},y={(GHimage.north west)}]}{%
\end{scope}\end{scope}
}

\newenvironment{IncludeClipGH}[2][\textwidth]{%
\def\GHClipImage{#2}
\begin{scope}
\node[anchor=south west,inner sep=0](GHimage){\phantom{\includegraphics[width=#1]{#2}}};
\begin{scope}[x={(GHimage.south east)},y={(GHimage.north west)}]}{%
\end{scope}\end{scope}
}

\pgfkeys{GHShowDetail/.cd,
width/.code                    = \def\GH@width{#1},
height/.code                   = \def\GH@height{#1},
/GHShowDetail/.unknown/.code   = {\let\searchname=\pgfkeyscurrentname
\pgfkeysalso{\searchname/.try=#1,
/tikz/\searchname/.retry=#1}}}

\def\GHShowDetail{\pgfutil@ifnextchar[{\GH@ShowDetail}{\GH@ShowDetail[]}}
\def\GH@ShowDetail[#1] at (#2,#3)#4{
\pgfkeys{GHShowDetail/.cd,
width   = 0.1,
height  = 0.1}
\pgfqkeys{/GHShowDetail}{#1}
\path (#2,#3)--++(\GH@width/2,\GH@height/2) coordinate (rightnode)
(#2,#3)--++(-\GH@width/2,-\GH@height/2) coordinate (leftnode);
\node [fit=(leftnode) (rightnode),
ultra thick,draw,
color= lightgray,
](#4)  {};}

\pgfkeys{GHShowPath/.cd,
/GHShowPath/.unknown/.code   = {\let\searchname=\pgfkeyscurrentname
\pgfkeysalso{\searchname/.try=#1,
/tikz/\searchname/.retry=#1}}}

\def\GHShowPath{\pgfutil@ifnextchar[{\GH@ShowPath}{\GH@ShowPath[]}}
\def\GH@ShowPath[#1]#2{
\pgfqkeys{/GHShowPath}{#1}
\draw[#1] #2 -- cycle;
}

\def\GHShowClipPath{\pgfutil@ifnextchar[{\GH@ShowClipPath}{%
\GH@ShowClipPath[]}}
\def\GH@ShowClipPath[#1]#2{
\pgfqkeys{/GHShowPath}{#1}
\clip  #2 -- cycle;
\node[anchor    = south west,
inner sep = 0](GHimage){%
\includegraphics[width=12cm]{\GHClipImage}};
}

\newif\ifanchor@show\anchor@showfalse
\pgfkeys{GHAnchor/.cd,
color/.code         = \def\GH@anchor@col{#1},
show/.is if         = anchor@show,
show/.default       = true}

\def\GHAnchor{\pgfutil@ifnextchar[{\GH@Anchor}{\GH@Anchor[]}}
\def\GH@Anchor[#1] at (#2,#3)#4{%
\pgfkeys{/GHAnchor/.cd,
color  = gray,
show   = false}
\pgfqkeys{/GHAnchor}{#1}
\coordinate (#4) at (#2,#3);
}%

\pgfkeys{GHShowGrid/.cd,
color/.code         = \def\GH@grid@col{#1},
space/.code         = \def\GH@grid@space{#1},
step/.code          = \def\GH@grid@step{#1},
precision/.code     = \def\GH@grid@precision{#1},
}%

\def\GHShowGrid{\pgfutil@ifnextchar[{\GH@ShowGrid}{\GH@ShowGrid[]}}
\def\GH@ShowGrid[#1]{%
\pgfkeys{/GHShowGrid/.cd,
color  = lightgray,
space = 0.04,
step=0.1,
precision = 1}
\pgfqkeys{/GHShowGrid}{#1}
\foreach \x in {0,\GH@grid@step,...,1.001}{%
\draw[\GH@grid@col] (0,\x) ++(-\GH@grid@space,0) node[left]{%
\pgfmathprintnumber[fixed,fixed zerofill,precision=\GH@grid@precision]
{\x}} -- (1,\x);
\draw[\GH@grid@col] (\x,0) ++(0,-\GH@grid@space)node[rotate=90,left]{%
\pgfmathprintnumber[fixed,fixed zerofill,precision=\GH@grid@precision]
{\x}} -- (\x,1);}}

\pgfkeys{GHspy/.cd,
color/.code         = \def\GH@anchor@col{#1},
}

\def\GHspy#1#2(#3,#4){%
\spy  on (#1) in node at ([shift={(#3,#4)}]GHimage.#2);
}
\makeatother

\begin{document}

\begin{tikzpicture}
\tikzset{spy style/.style={spy using outlines={circle, magnification=4, size=3cm, connect spies}}}

\begin{IncludeGH}[12cm]{champignon.jpeg}
\GHShowGrid[color=lightgray,step=.1,precision=1]
\GHShowDetail[shape=circle,color=red,width=.2] at (0.25,0.5){cercle}
\GHShowDetail[shape=rectangle,width=.1,height=.1] at (0.7,0.7){rec}
\GHspy{cercle}{south}(-4,-3)
\GHShowPath[ultra thick,red]{(0.5,0.75) -- (0.90,0.75) -- (0.90,0.5) .. controls (0.8,-0.2) and (0.65,0.2) .. (0.5,0.3)}
\end{IncludeGH}
\end{tikzpicture}

\begin{tikzpicture}
\begin{IncludeClipGH}[12cm]{champignon.jpeg}
\GHShowClipPath[red]{(0.5,0.75) -- (0.90,0.75) --
(0.90,0.5) .. controls (0.8,-0.2) and (0.65,0.2) .. (0.5,0.3)}
\end{IncludeClipGH}
\end{tikzpicture}
\end{document}


I am not using Bezier. It is just for fun.

\documentclass{article}
\usepackage{graphicx,pstricks,pst-func}

\newsavebox\IBox
\savebox\IBox{\includegraphics[width=\linewidth]{Images/food}}

\newdimen\width
\newdimen\height
\width=\wd\IBox
\height=\ht\IBox

\def\function
{
\psparametricplot{0}{2.5 .25 exp}{t^2  | 0.8*(sqrt(2.5-t^4)+t)}
\psparametricplot{2.5 .25 exp}{0}{t^2  | 0.8*(-sqrt(2.5-t^4)+t)}
\psparametricplot{0}{2.5 .25 exp}{-t^2 | 0.8*(-sqrt(2.5-t^4)+t)}
\psparametricplot{2.5 .25 exp}{0}{-t^2 | 0.8*(sqrt(2.5-t^4)+t)}
}

\pagestyle{empty}

\begin{document}
\centering
\begin{pspicture}(\width,\height)
\rput[lb](0,0){\usebox\IBox}
\pscustom[unit=2.3cm, origin={0.5\width,0.4\height}, linecolor=cyan, dimen=middle, linewidth=3pt, algebraic]{\function}
\psgrid[gridwidth=0.2pt, gridcolor=white, subgriddiv=1]
\end{pspicture}

\vspace{1cm}
\begin{pspicture}(\width,\height)
\psclip{\pscustom[unit=2.3cm, origin={0.5\width,0.4\height}, linestyle=none, algebraic]{\function}}
\rput[lb](0,0){\usebox\IBox}
\endpsclip
\psgrid[gridwidth=0.2pt, gridcolor=white, subgriddiv=1]
\end{pspicture}
\end{document}


This is a clipper with bezier curves.

\documentclass[pstricks,border={-8.5mm -5.5mm -8.5mm -5.0mm}]{standalone}
\usepackage{pst-eucl,graphicx}

\psset
{
runit=\psunit,
fillstyle=solid,
PointName=none,
PointSymbol=none,
}

\pstVerb
{
/theta 72 def
/Major 6.0 def
/Minor 3.3 def
% b a t p2c ---> x y
% where b (semi-minor), a (semi-major), t (theta)
/p2c {dup 3 1 roll cos mul 3 1 roll sin mul} bind def
}

\def\DeclareNodes
{
\pstGeonode
(0,-8){Bottom}
(0,8){Top}
(0,0){center}
(0,2.7){A}
(0.5,2.7){B}
(1,3.25){C}
(1.2,1.3){D}
(1.3,1.0){E}
(2.0,1.0){F}
(3.0,1.0){G}
(3.0,2.2){H}
(!Minor Major theta p2c){I}
(!Minor Major theta neg p2c){J}
(4,-2){K}
(4,0){L}
(2.2,-1.8){M}
(1.5,-1){N}
(1,-1){O}
(0,-3.2){P}
\pstOrtSym{Bottom}{Top}{B,C,D,E,F,G,H,I,J,K,L,M,N,O}
}

\def\RightPart
{
\psline(A)(B)(C)
\psbezier(D)(E)(F)
\psbezier(G)(H)(I)
\psellipticarcn[dimen=middle](center)(!Major Minor){(I)}{(J)}
\psbezier(K)(L)(M)
\psbezier(N)(O)(P)
}

\def\LeftPart
{
\psbezier(O')(N')(M')
\psbezier(L')(K')(J')
\psellipticarcn[dimen=middle](center)(!Major Minor){(J')}{(I')}
\psbezier(H')(G')(F')
\psbezier(E')(D')(C')
\psline(B')
}

\begin{document}

%\begin{pspicture}[showgrid=top](-7,-4)(7,4)
%    \DeclareNodes
%    \pscustom*{\RightPart\LeftPart\closepath}
%\end{pspicture}

\begin{pspicture}[showgrid=false](-7,-4)(7,4)
\begin{psclip}{\DeclareNodes\pscustom[linewidth=2mm,linecolor=red]{\RightPart\LeftPart\closepath}}
\rput(0,0){\includegraphics[width=14\psunit]{herbert}}
\end{psclip}
\end{pspicture}

\end{document}


Edit:

Another similar method can be seen here.