PGM to OpenSCAD surface

by sawdusty, published

PGM to OpenSCAD surface by sawdusty Apr 17, 2013

Thing Info

4618Views 622Downloads
Report Thing


This is a quick and (very) simple Python script to read data from an ASCII format PGM (portable gray map) file and convert it to a "surface" data file for OpenSCAD.

You will need Python (written for v2.7), and numpy to run it, but it's quick to convert. You will need OpenSCAD to utilize the output of this script.


Unlike a certain other "lithopane" thing, this is not limited to a small image size. However, you must be able to convert your original photo to a PGM file. You can do that quite easily with either IrfanView or with ImageMagick. I'm sure there are a dozen (at least) other tools that can do this too, but you need to make sure the PGM file is ASCII formatted (not binary) and that is has no (0) compression.

1) Edit your digital image, then convert to PGM.

2) Run this script with Python 2.7 like this:
python pgm2surf.py myImage.pgm myImageSurf.dat

3) In OpenSCAD, use the "surface" command to import the DAT file, like this:
surface(file = "c:/myCoolStuff/myImageSurf.dat", center = false, convexity = 10);

1) The surface is flipped both top to bottom and left to right when you create the surface in OpenSCAD. You can plan accordingly by editing your image in the photo editor before creating the PGM file.

2) There is a "depth" value in this script that reduces the heights of the surface values. I've set it to 0.03 after several trials, but you might want to play with that value, depending on your purpose for the surface. A value of 0.5 yields a surface that has a very high relief from the highest point to the lowest. It might be good if you want to create a mold of the image.
The depth value can be set as the last argument on the command line when calling the script, like this:
python pgm2surf.py myImage.pgm myImageSurf.dat 0.5

3) For a "cookie cutter" type mold, you want to "invert" your photo (create the negative) before creating the PGM file. Try it and see.

4) My apologies to Linux users, the typical python directive is missing from the top of the script. Please add it if you need it.

(BTW, the image example shown above is from a photo taken just after my parents' wedding, 50 years ago. They celebrated their 50th anniversary last week. Happy Anniversary! Now immortalized on the Internet.)

While trying to get OpenSCAD to generate an STL file from the surface data, I found that it crashes... more often than not. The problem seems to be the number of vertices in the generated surface. I've been successful in generating an STL from a surface as large as 162 x 200 (pixels in the PGM file) but anything large crashes OpenSCAD. YMMV. (Yes, that means the example image I showed is very unrealistic... oops!)

Thing Info

4618Views 622Downloads
Report Thing

Liked By

View All


Give a Shout Out

If you print this Thing and display it in public proudly give attribution by printing and displaying this tag. Print Thing Tag

All Apps

No results.

Any tip on how to add a frame and a hanging hole in OpenSCAD? I can't figure it out...

I think the easiest way to add a smooth frame around a surface would be to edit the image before you generated the PGM file. Add a gray border around the image in your photo editor. The darker the gray tone, the higher the frame will be. If you want a thin (light) frame, make it lighter gray. If you added some white circles in the border then you'd have a starting point for drilling mounting holes too. If that doesn't help, then you'll need to learn to use the difference() function in OpenSCAD.

My apologies on the (glacially) slow reply. I think the PGM file might not be in the format recognized by the Python code. That's about the best guess I have without knowing more about your input file and how it was created.
Some programs that generate PGM files will add comments in the beginning of the file, and they might not be handled well. It's no stretch to say that this code would not exit gracefully in that situation.

Is there a public repository for this code, to be able to follow and fork?

No, I haven't thought about adding the code for this to a public repository. I have not had time to work on this again, though some recent interesting activity in Thingiverse has made me want to get back to it.