3

I have some complex code that creates a tikz picture, called image A. The background areas of this picture are white, as are some foreground areas, which are painted with a white fill. I now want to lay this picture on top of image B, such that all white parts of image A are rendered transparent.

It would be ideal if image A could be created so that the white areas were simply not painted, but this is not possible, because many of the white areas are curve paths---so it's easy to draw them directly, but hard to draw their complement.

Can this be done? At the moment I'm having to render images A and B separately, take screenshots, and do this layering in GIMP.

An example (added by another user):

First draw a shape using white to 'erase' parts:

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}
    \path[fill=cyan] (0,0) circle (1);
    \path[draw=white, line width=10pt] (-0.1,-1.2) to[out=70, in=-70] (-0.1,1.2);
\end{tikzpicture}

\end{document}

enter image description here

Now try drawing something behind it:

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}
    \path[draw=orange, line width=5pt] (-1.5,0) -- (1.5,0);
    \path[fill=cyan] (0,0) circle (1);
    \path[draw=white, line width=10pt] (-0.1,-1.2) to[out=70, in=-70] (-0.1,1.2);
\end{tikzpicture}

\end{document}

enter image description here

The goal is to have the orange line go behind the blue areas but show through the white part, so you can see a segment of the orange line in between the two blue regions.

4
  • 2
    Yes, I think so. But I need an example to play with. You probably need to do it all in one picture, but presumably that shouldn't be a problem. At least, the way I'm thinking might work probably needs that. But, like I say, hard to know without something to fiddle with.
    – cfr
    Commented Oct 29, 2016 at 0:27
  • tikzfadingfrompicture or transparency group. Cannot tell for sure. Perhaps tex.stackexchange.com/a/323315/51022 helps
    – Symbol 1
    Commented Oct 29, 2016 at 5:12
  • I hope you don't mind that I added an example. I could ask my own question if you prefer, but apart from the example it would be exactly the same as your question.
    – N. Virgo
    Commented Jul 21, 2023 at 9:43
  • 1
    @N.Virgo The linked solution by Symbol 1 ist in my opinion easier to achieve but not every viewer renders it the same way, so it might not be as portable as the more complex spath3 solution (which is also not exactly the same but close enough for this example). Commented Jul 21, 2023 at 12:56

2 Answers 2

4

This is easy to achieve using spath3 and intersections TikZ libraries.

You need to create the paths (but not draw them), save them and then intersect the circle with the two arcs and get the components. spath3 allow all these operations.

For example, something like this:

\usetikzlibrary{intersections,spath3}

\begin{document}
\begin{tikzpicture}[line join=round]
% orignal paths:
\path[draw=orange,line width=5pt] (-1.5,0) -- (1.5,0);
\path[spath/save=A] (0,0) circle (1);
\path[spath/save=B,xshift=-5pt] (-0.1,-1.2) to[out=70, in=-70] (-0.1,1.2);
\path[spath/save=C,xshift= 5pt] (-0.1,-1.2) to[out=70, in=-70] (-0.1,1.2);
% spath3 operatios:
\tikzset
{
  spath/split at intersections={A}{B},
  spath/split at intersections={A}{C},
  spath/get components of={A}\Acpts,
  spath/get components of={B}\Bcpts,
  spath/get components of={C}\Ccpts,
}
% new paths
\fill[cyan,
      spath/use=\getComponentOf\Acpts{2},
      spath/use={\getComponentOf\Bcpts{2},weld},
     ];
\fill[cyan,
      spath/use=\getComponentOf\Acpts{4},
      spath/use={\getComponentOf\Ccpts{2},reverse,weld},
     ];
\end{tikzpicture}
\end{document}

enter image description here

2

I'm not aware of a way to do this while keeping the images in a vector format. However, as you are already using GIMP, and thus converting to bitmap, I assume you don't mind that too much. If so, the process can be automated using some command line tools. Here is a bash script that does this:

#!/bin/bash
# input files expected in pdf, output in png
bg_pdf=$1
fg_pdf=$2
output_png=$3

# generate png file names
bg_png=${bg_pdf%.pdf}.png
fg_png=${fg_pdf%.pdf}.png

# first, convert both pdf files to png. The best tool for this
# is pdftoppm from popplerutils. We switch off antialasing
# of fonts (-aa no) and other elements (--aaVector no) in
# order to avoid ghosting at the edges. The -r option sets the
# resolution (pixels in the output image per inch of input image).
# Use a high enough resolution, you can always reduce image size 
# (and maybe apply antialising) later. 

pdftoppm -r 300 -png -aa no -aaVector no $bg_pdf > $bg_png
pdftoppm -r 300 -png -aa no -aaVector no $fg_pdf > $fg_png

# now, we use imagemagick's convert to convert white to transparency in the
# foreground image

convert $fg_png -transparent white $fg_png

# finally, we use imagemagick's composite to stack them on top of each other.
# the -gravity center option centers the images to each other; it is not
# needed if they are of equal size.

composite -gravity center $fg_png $bg_png $output_png

# you could also use convert to reduce size and apply antialias
# convert $output_png -antialias -resize 50% halfsize.png

Save this as script.sh and make executable (chmod +x script.sh). Call this like

./script.sh background.pdf foreground.pdf composite.png

A breathtakingly beautiful example (input files uploaded as PNG, but I tested at home on the PDF originals):

Background background

Foreground foreground

Composite enter image description here

1
  • 3
    I don't doubt that it is a good answer, but I see no TeX-LaTeX code in it...
    – CarLaTeX
    Commented Oct 29, 2016 at 6:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .