I was on Pinterest and saw this image. It is pretty new to me and I have no idea where to start? How would you achieve this in any program? Please help me.

Strange looking Apple logo.

  • 2
    Hi. Welcome to GDSE. What have you tried? What has failed? We like to answer questions here, but we expect at least some effort from users. GDSE isn't a tutorial on demand site. Also note the Apple logo is trademarked, and doing anything to it is illegal.
    – Billy Kerr
    Commented Aug 14, 2021 at 18:14
  • Sorry, that is my bad. If it is so, then please delete this post. Commented Aug 14, 2021 at 18:26
  • 6
    @user287001 when editing you should not be adding things to the post that the author didn’t intend.
    – Tim
    Commented Aug 15, 2021 at 9:06

3 Answers 3


It's all a bit easier to discuss if we start with horizontal lines, like so:

Version with horizontal lines

As Ilmari Karonen said, this is just a displacement map. You start with a 3D topography h(x,y), and then each point (x,y) in the result should use the line starting at y0 = yh(x,y).

With raster graphics, this can be rendered straight away, but to get clean vector lines we'd actually need to work the other way around: each line should be parameterised as

fy0(x) = y0 + h(x, fy0(x))

The problem is that this is only an implicit defining equation, because the RHS contains y = fy0(x). This could be solved with Newton-Raphson, but there's a simpler way: just construct the lines going from left to right, and at each point go up or down as needed to fulfill the equation. Assuming continuity, this is always just a small update, so we can approximate h as constant there.

Implementation in Haskell:

type ℝ = Double

horizContourLine ::
     ((ℝ,ℝ) -> ℝ) -- ^ The topography/height function
  -> (ℝ,ℝ)        -- ^ x-interval on which to render the path
  -> ℝ            -- ^ Step size / resolution along the path
  -> ℝ            -- ^ Base-level y-coordinate of the line
  -> [(ℝ,ℝ)]      -- ^ Trail line
horizContourLine h (x₀,xe) δx y₀ = go (x₀,y₀)
 where go (x,y) = (x,yTgt)
            : if x<xe then go (x+δx, yTgt) 
                      else []
        where yTgt = y₀ + h (x,y)

Then, with a suitable image input like

example image input

we get contours like

result for the pear example

Full code: https://gist.github.com/leftaroundabout/8b7075d25adecdf16806ea5d7a7ea2aa

Rotation to diagonal lines is left as an exercise.


This is basically just a displacement map applied to a bunch of lines.

The tricky part is that applying a displacement map to a bitmap texture will stretch and compress the entire texture, including both the lines and the gaps between them. To get the shading effect in your example image, you'll want to stretch only the gaps, not the lines themselves. I can see two (or maybe three) ways around this:

  1. Use a vector image editor that can be configured to only displace the path of the lines while leaving their width unchanged. I'm not sure if any common off-the-shelf vector drawing software (Illustrator, Inkscape, etc.) supports this, but if they do, that would probably yield the cleanest result.

  2. In a bitmap editor (Photoshop, GIMP, etc.), start with a texture consisting of alternating black and white stripes of equal width, apply the displacement map to that, then use an edge detection filter to convert the stripe boundaries into lines (or maybe auto-trace the displaced stripe boundaries in a vector drawing program). The risk here is that, unless you work at a very high resolution (and then scale the final result down), the quality may suffer due to aliasing.

  3. Write your own software to do one of the above. Obviously this requires some programming skills that not everybody has, but as far as graphics programming tasks go, this actually shouldn't be a particularly hard one.

I actually tested option 2 using the displace filter in GIMP. Unfortunately I don't really have time to write a step-by-step walkthrough right now (maybe later…), but as a teaser, here's the final result of my quick experiment:

Final result


The "displacement" mentioned by Ilmari Karonen and "relief effect" mentioned by Abdul Qayum are almost the same thing.

Here are some pictures from Image Relief Algorithm and its Application in Security Printing. We use an image to make cells (or grids) irregular (or to have a displacement), and then draw parrallel lines on them.

You can implement this algorithm by hands or use a software, such as GIMP displacement map or JURA (used by Abdul Qayum).

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.