{"id":21406008,"url":"https://github.com/jes/pngcam","last_synced_at":"2025-09-13T16:39:48.736Z","repository":{"id":137662558,"uuid":"304027360","full_name":"jes/pngcam","owner":"jes","description":"Pngcam takes in a heightmap and gives out Gcode to run a CNC machine.","archived":false,"fork":false,"pushed_at":"2023-09-29T20:06:40.000Z","size":1491,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-23T03:44:01.303Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"G-code","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-14T13:40:16.000Z","updated_at":"2023-09-14T19:10:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"73b56b30-e49a-44ca-9377-5c1c961d023a","html_url":"https://github.com/jes/pngcam","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jes%2Fpngcam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jes%2Fpngcam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jes%2Fpngcam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jes%2Fpngcam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jes","download_url":"https://codeload.github.com/jes/pngcam/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243902297,"owners_count":20366260,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-22T16:30:03.502Z","updated_at":"2025-03-16T17:13:12.828Z","avatar_url":"https://github.com/jes.png","language":"G-code","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pngcam\n\nPngcam takes in a heightmap and gives out Gcode to run a CNC machine.\n\nI wrote a bit about it in https://incoherency.co.uk/blog/stories/cnc-heightmap-toolpaths.html\n\nPngcam also includes a heightmap rendering program called pngcam-render.\n\n## Building\n\nDependencies:\n\n - perl\n - GD\n\nYou can install GD on Ubuntu with:\n\n    $ sudo apt install libgd-perl\n\nTo build the \"semi-fat-packed\" Perl scripts:\n\n    $ make\n\nTo install it to `/usr/bin/`:\n\n    $ sudo make install\n\nIf you want to run it without building, then you can use something like:\n\n    $ PERL5LIB=lib ./pngcam [...]\n\nIf you want to use `--write-stock` then you'll need `pngcam-plotter` which is built by the `Makefile`.\n\n## Usage\n\nYou'll need to represent your part in a heightmap in a PNG file.\nThe brightness of a pixel (defined as average of r,g,b) corresponds to the height, such that white is the highest and black\nis the lowest.\n\nAs an example, let's look at first roughing out a shape with a 6mm end mill, and then move to a 2mm ball-nose end mill to finish up the part.\nWith both tools we'll get 2 passes over the part: one horizontal, and one vertical.\n\nWe'll start with the toolpath for the 6mm end mill. We'll have a maximum step-down of 1mm and step-over of 5mm, at 10000 rpm, and\nwe'll leave 0.25mm clearance from the final part for the finish pass.\n\nLet's say we want the width of the heightmap to correspond to 100mm in the part, and we want the full brightness range to cover 10mm depth.\n\n    $ pngcam --width 100 --depth 10 --tool-shape flat --tool-diameter 6 --step-down 1 --step-over 5 --speed 10000 --clearance 0.5 heightmap.png \u003e pass1.gcode\n\nAnd then essentially the same again, but this time with the 2mm ball-nose end mill, with reduced step-over and increased spindle speed.\n\n    $ pngcam --width 100 --depth 10 --tool-shape ball --tool-diameter 2 --step-down 1 --step-over 0.2 --speed 20000 heightmap.png \u003e pass1.gcode\n\nThe (0,0,0) point will be at the top left of the input image, with the part existing in the positive X direction and negative Y direction, and\nwith Z=0 at the top surface of the part (i.e. at \"white\" in the heightmap).\n\n## Options\n\n    $ pngcam --usage\n    Usage: pngcam [options] PNGFILE \u003e GCODEFILE\n\n    This program will read in a heightmap from PNGFILE and write G-code to stdout.\n\n    Tool options:\n\n        --tool-shape flat|ball\n            Set the shape of the end mill.\n            Default: ball\n\n        --tool-diameter MM\n            Set the diameter of the end mill in mm.\n            Default: 6\n\n    Tool control options:\n\n        --step-down MM\n            Set the maximum step-down in mm. Where the natural toolpath would exceed a cut of this depth, multiple passes are taken instead.\n            Default: 100\n\n        --step-over MM\n            Set the distance to move the tool over per pass in mm.\n            Default: 5\n\n        --step-forward MM\n            Set the distance to step forward for each point in the path. If the part contains features that are substantially smaller\n            than the step-over, then you can use --step-forward to make sure you don't cut through them.\n            Default: takes value from --step-over\n\n        --xy-feed-rate MM/MIN\n            Set the maximum feed rate in X/Y plane in mm/min.\n            Default: 400\n\n        --z-feed-rate MM/MIN\n            Set the maximum feed rate in Z axis in mm/min.\n            Default: 50\n\n        --rapid-feed-rate MM/MIN\n            Set the maximum feed rate for rapid travel moves in mm/min.\n            Default: 10000\n\n        --speed RPM\n            Set the spindle speed in RPM.\n            Default: 10000\n\n    Path generation options:\n\n        --roughing-only\n            Only do the roughing pass (based on --step-down) and do not do the finish pass. This is useful if you\n            want to use different parameters, or a different tool, for the roughing pass compared to the finish pass.\n            Default: do the finish pass as well as the roughing pass\n\n        --clearance MM\n            Set the clearance to leave around the part in mm. Intended so that you can come back again with a finish pass to clean up the part.\n            Default: 0\n\n        --rapid-clearance MM\n            Set the Z clearance to leave above the part during rapid moves.\n            Default: 5\n\n        --route horizontal|vertical|both\n            Set whether the tool will move in horizontal lines, vertical lines, or first horizontal followed by vertical.\n            Default: both\n\n        --x-offset MM\n            Set the offset of X cordinates.\n            Default: 0\n\n        --y-offset MM\n            Set the offset of Y cordinates.\n            Default: 0\n\n        --z-offset MM\n            Set the offset of Z cordinates.\n            Default: 0\n\n        --ramp-entry\n            Add horizontal movements to plunge cuts where possible, to reduce cutting forces.\n            Default: plunge straight down\n\n    Heightmap options:\n\n        --width MM\n            Set the width of the image in mm. If height is not specified, height will be calculated automatically to maintain aspect ratio. If neither are specified, width=100mm is assumed.\n            Default: 100\n\n        --height MM\n            Set the height of the image in mm. If width is not specified, width will be calculated automatically to maintain aspect ratio. If neither are specified, width=100mm is assumed.\n            Default: N/A\n\n        --depth MM\n            Set the total depth of the part in mm.\n            Default: 10\n\n        --x-flip\n            Flip the image in the X axis. This is useful when you want to cut the same shape on the bottom of a part. The origin will still be at top left of the finished toolpath.\n\n        --y-flip\n            Flip the image in the Y axis. This is useful when you want to cut the same shape on the bottom of a part. The origin will still be at top left of the finished toolpath.\n\n        --invert\n            Invert the colours in the image, so that white is the deepest cut and black is the shallowest.\n\n        --deep-black\n            Let the tool cut below the full depth into black (0,0,0) if this would allow better reproduction of the non-black parts of the heightmap.\n            Only really applicable with a ball-nose end mill.\n            Default: treat black (0,0,0) as a hard limit on cut depth\n\n        --beyond-edges\n            Let the tool cut beyond the edges of the heightmap.\n            Default: don't\n\n        --omit-top\n            Don't bother cutting top surfaces that are at the upper limit of the heightmap.\n            Default: cut them\n\n        --normalise\n            Measure the minimum and maximum brightness in the heightmap and stretch all brightness so that the full range of cut depth is achieved.\n            Default: no normalisation\n\n        --normalise-ignore-black\n            When normalising, ignore black (i.e. stretch all brightnesses apart from black, but leave black alone).\n            Note that normalisation is applied before inversion, so if you need this with --invert, you might have to invert the image externally instead.\n            Default: don't ignore black\n\n        --imperial\n            All units are inches instead of mm, and inches/min instead of mm/min. G-code output has G20 instead of G21.\n            Default: not imperial.\n\n        --rgb\n            Use R,G,B channels independently to get 24 bits of height data instead of 8.\n            Default: greyscale\n\n        --read-stock PNGFILE\n            Read stock heightmap from PNGFILE, to save cutting air in roughing passes.\n            Default: none\n\n        --write-stock PNGFILE\n            Write output heightmap to PNGFILE, to use with --read-stock.\n            Default: none\n\n    Cycle time options:\n\n        --max-vel MM/MIN\n            Max. velocity in mm/min for cycle time calculation.\n            Default: 4000.\n\n        --max-accel MM/SEC^2\n            Max. acceleration in mm/sec^2 for cycle time calculation.\n            Default: 50.\n\n    Output options:\n\n        --quiet\n            Suppress output of dimensions, resolutions, and progress.\n\n## Pngcam-render options\n\n    $ pngcam-render --usage\n    Usage: pngcam-render [options] STLFILE\n\n    This program will read in the STLFILE and render it to a heightmap.\n\n    Options:\n\n        --border PX\n            Draw a border around the part.\n            Default: 32\n\n        --width PX\n            Set the width of the part in pixels. If height is not specified, height will be calculated\n            automatically to maintain aspect ratio. If neither are specified, width=400px is assumed.\n            The output image will be this wide, plus a border on both sides.\n            Default: 400\n\n        --height PX\n            Set the height of the part in pixels. If width is not specified, width will be calculated\n            automatically to maintain aspect ratio. If neither are specified, width=400px is assumed.\n            The output image will be this talg, plus a border on both sides.\n            Default: N/A\n\n        --bottom\n            View from the bottom, as if the part were rotated through 180 degrees around the Y axis.\n            Default: viewed from the top\n\n        --png PNGFILE\n            Set the name of the output file. If none is give, this will just be the STL file with \".png\" appended.\n            Default: STLFILE.png\n\n        --rgb\n            Use R,G,B channels independently to get 24 bits of height data instead of 8.\n            Default: greyscale\n\n        --quiet\n            Suppress output of dimensions, resolutions, and progress.\n\n## Tests\n\nTo run tests, either:\n\n    $ prove -l t/\n\nor\n\n    $ make test\n\nIf a test fails you might want to try diffing the old (expected) and new versions of the G-code files to work out what went wrong.\n\n## Contact\n\nPngcam is a program by James Stanley. You can email me at james@incoherency.co.uk or read my blog at https://incoherency.co.uk/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjes%2Fpngcam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjes%2Fpngcam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjes%2Fpngcam/lists"}