Update README
61
README.md
|
@ -1,61 +0,0 @@
|
|||
build/svg-render 2.0
|
||||
|
||||
Usage: build/svg-render [options]... [input_file] [output_file]
|
||||
|
||||
Specify "-" for stdin/stdout.
|
||||
|
||||
-h, --help
|
||||
Print help and exit
|
||||
-v, --version
|
||||
Print version and exit
|
||||
-o, --format
|
||||
Output format. Supported: gerber, svg, s-exp (KiCAD S-Expression)
|
||||
-p, --precision
|
||||
Number of decimal places use for exported coordinates (gerber: 1-9,
|
||||
SVG: 0-*)
|
||||
--clear-color
|
||||
SVG color to use for "clear" areas (default: white)
|
||||
--dark-color
|
||||
SVG color to use for "dark" areas (default: black)
|
||||
-d, --trace-space
|
||||
Minimum feature size of elements in vectorized graphics
|
||||
(trace/space) in mm. Default: 0.1mm.
|
||||
--no-header
|
||||
Do not export output format header/footer, only export the
|
||||
primitives themselves
|
||||
--flatten
|
||||
Flatten output so it only consists of non-overlapping white
|
||||
polygons. This perform composition at the vector level. Potentially slow.
|
||||
--no-flatten
|
||||
Disable automatic flattening for KiCAD S-Exp export
|
||||
--dilate
|
||||
Dilate output gerber primitives by this amount in mm. Used for
|
||||
masking out other layers.
|
||||
-g, --only-groups
|
||||
Comma-separated list of group IDs to export.
|
||||
-b, --vectorizer
|
||||
Vectorizer to use for bitmap images. One of poisson-disc (default),
|
||||
hex-grid, square-grid, binary-contours, dev-null.
|
||||
--vectorizer-map
|
||||
Map from image element id to vectorizer. Overrides --vectorizer.
|
||||
Format: id1=vectorizer,id2=vectorizer,...
|
||||
--force-svg
|
||||
Force SVG input irrespective of file name
|
||||
--force-png
|
||||
Force bitmap graphics input irrespective of file name
|
||||
-s, --size
|
||||
Bitmap mode only: Physical size of output image in mm. Format: 12.34x56.78
|
||||
--sexp-mod-name
|
||||
Module name for KiCAD S-Exp output
|
||||
--sexp-layer
|
||||
Layer for KiCAD S-Exp output. Defaults to auto-detect layers from
|
||||
SVG layer/top-level group names
|
||||
-a, --preserve-aspect-ratio
|
||||
Bitmap mode only: Preserve aspect ratio of image. Allowed values
|
||||
are meet, slice. Can also parse full SVG preserveAspectRatio syntax.
|
||||
--no-usvg
|
||||
Do not preprocess input using usvg (do not use unless you know
|
||||
*exactly* what you're doing)
|
||||
-e, --exclude-groups
|
||||
Comma-separated list of group IDs to exclude from export. Takes
|
||||
precedence over --only-groups.
|
191
README.rst
|
@ -1,46 +1,168 @@
|
|||
Gerbolyze high-resolution image-to-PCB converter
|
||||
================================================
|
||||
Gerbolyze high-fidelity SVG/PNG/JPG to PCB converter
|
||||
====================================================
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/jaseg/gerbolyze/master/sample1.jpg
|
||||
Gerbolyze renders SVG vector and PNG/JPG raster images into existing gerber PCB manufacturing files.
|
||||
Vector data from SVG files is rendered losslessly *without* an intermediate rasterization/revectorization step.
|
||||
Still, gerbolyze supports (almost) the full SVG 1.1 spec including complex, self-intersecting paths with holes,
|
||||
patterns, dashes and transformations
|
||||
|
||||
Raster images can either be vectorized through contour tracing (like gerbolyze v1.0 did) or they can be embedded using
|
||||
high-resolution grayscale emulation while (mostly) guaranteeing trace/space design rules.
|
||||
|
||||
.. image:: pics/pcbway_sample_02_small.jpg
|
||||
|
||||
Tooling for PCB art is quite limited in both open source and closed source ecosystems. Something as simple as putting a
|
||||
pretty picture on a PCB can be an extremely tedious task. Depending on the PCB tool used, various arcane incantations
|
||||
may be necessary and even modestly complex images will slow down most PCB tools to a crawl.
|
||||
|
||||
Gerbolyze solves this problem in a toolchain-agnostic way by directly vectorizing bitmap files onto existing gerber
|
||||
layers. Gerbolyze has been tested against both the leading open-source KiCAD toolchain and the industry-standard Altium
|
||||
Designer. Gerbolyze is written with performance in mind and will happily vectorize tens of thousands of primitives,
|
||||
generating tens of megabytes of gerber code without crapping itself. With gerbolyze you can finally be confident that
|
||||
your PCB fab's toolchain will fall over before yours does if you overdo it with the high-poly anime silkscreen.
|
||||
Gerbolyze solves this problem in a toolchain-agnostic way by directly vectorizing SVG vector and PNG or JPG bitmap files
|
||||
onto existing gerber layers. Gerbolyze processes any spec-compliant SVG and "gerbolyzes" SVG vector data into a Gerber
|
||||
spec-compliant form. Gerbolyze has been tested against both the leading open-source KiCAD toolchain and the
|
||||
industry-standard Altium Designer. Gerbolyze is written with performance in mind and will happily vectorize tens of
|
||||
thousands of primitives, generating tens of megabytes of gerber code without crapping itself. With gerbolyze you can
|
||||
finally be confident that your PCB fab's toolchain will fall over before yours does if you overdo it with the high-poly
|
||||
anime silkscreen.
|
||||
|
||||
.. image:: pics/process-overview.png
|
||||
|
||||
.. contents::
|
||||
|
||||
Produce high-quality artistic PCBs in three easy steps!
|
||||
-------------------------------------------------------
|
||||
Tl;dr: Produce high-quality artistic PCBs in three easy steps!
|
||||
--------------------------------------------------------------
|
||||
|
||||
Gerbolyze works in three steps.
|
||||
|
||||
1. Generate a scale-accurate preview of the finished PCB from your CAD tool's gerber output:
|
||||
1. Generate a scale-accurate template of the finished PCB from your CAD tool's gerber output:
|
||||
|
||||
.. code::
|
||||
|
||||
$ gerbolyze render top my_gerber_dir preview.png
|
||||
$ gerbolyze template --top template_top.svg [--bottom template_bottom.svg] my_gerber_dir
|
||||
|
||||
2. Load the resulting preview image into the GIMP or another image editing program. Use it as a guide to position scale
|
||||
your artwork. Create a black-and-white image from your scaled artwork using GIMP's newsprint filter. Make sure most
|
||||
details are larger than about 10px to ensure manufacturing goes smooth.
|
||||
2. Load the resulting template image Inkscape_ or another SVG editing program. Put your artwork on the appropriate SVG
|
||||
layer. Dark colors become filled gerber primitives, bright colors become unfilled primitives. You can directly put
|
||||
raster images (PNG/JPG) into this SVG as well, just position and scale them like everything else. SVG clips work for
|
||||
images, too. Masks are not supported.
|
||||
|
||||
3. Vectorize the resulting grayscale image drectly into the PCB's gerber files:
|
||||
3. Vectorize the edited SVG template image drectly into the PCB's gerber files:
|
||||
|
||||
.. code::
|
||||
|
||||
$ gerbolyze vectorize top input_gerber_dir output_gerber_dir black_and_white_artwork.png
|
||||
$ gerbolyze paste --top template_top_edited.svg [--bottom ...] my_gerber_dir output_gerber_dir
|
||||
|
||||
Image preprocessing guide
|
||||
-------------------------
|
||||
Features
|
||||
--------
|
||||
|
||||
Nice black-and-white images can be generated from any grayscale image using the GIMP's newsprint filter. The
|
||||
straight-forward pre-processing steps necessary for use by ``gerbolyze vectorize`` are as follows.
|
||||
Input on the left, output on the right.
|
||||
|
||||
.. image:: pics/test_svg_readme_composited.png
|
||||
|
||||
* Almost full SVG 1.1 static spec coverage (!)
|
||||
|
||||
* Paths with beziers, self-intersections and holes
|
||||
* Strokes, even with dashes and markers
|
||||
* Pattern fills and strokes
|
||||
* Transformations and nested groups
|
||||
* Proper text rendering with support for complex text layout (e.g. Arabic)
|
||||
* <image> elements via either built-in vectorizer or built-in halftone processor
|
||||
* (some) CSS
|
||||
|
||||
* Writes Gerber, SVG or KiCAD S-Expression (``.kicad_mod``) formats
|
||||
* Can export from top/bottom SVGs to a whole gerber layer stack at once with filename autodetection
|
||||
* Can export SVGs to ``.kicad_mod`` files like svg2mod (but with full SVG support)
|
||||
* Beziers flattening with configurable tolerance using actual math!
|
||||
* Polygon intersection removal
|
||||
* Polygon hole removal (!)
|
||||
* Optionally vector-compositing of output: convert black/white/transparent image to black/transparent image
|
||||
* Renders SVG templates from input gerbers for accurate and easy scaling and positioning of artwork
|
||||
* layer masking with offset (e.g. all silk within 1mm of soldermask)
|
||||
* Can read gerbers from zip files
|
||||
|
||||
Gerbolyze is the end-to-end "paste this svg into these gerbers" command that handles all layers on both board sides at
|
||||
once. The heavy-duty computer geometry logic of gerbolyze is handled by the svg-flatten utility (``svg-flatten``
|
||||
directory). svg-flatten reads an SVG file and renders it into a variety of output formats. svg-flatten can be used like
|
||||
a variant of the popular svg2mod that supports all of SVG and handles arbitrary input ``<path>`` elements.
|
||||
|
||||
Algorithm Overview
|
||||
------------------
|
||||
|
||||
This is the algorithm gerbolyze uses to process a stack of gerbers.
|
||||
|
||||
* Map input files to semantic layers by their filenames
|
||||
* For each layer:
|
||||
|
||||
* load input gerber
|
||||
* Pass mask layers through ``gerbv`` for conversion to SVG
|
||||
* Pass mask layers SVG through ``svg-flatten --dilate``
|
||||
* Pass input SVG through ``svg-flatten --only-groups [layer]``
|
||||
* Overlay input gerber, mask and input svg
|
||||
* Write result to output gerber
|
||||
|
||||
This is the algorithm svg-flatten uses to process an SVG.
|
||||
|
||||
* pass input SVG through usvg_
|
||||
* iterate depth-first through resulting SVG.
|
||||
|
||||
* for groups: apply transforms and clip and recurse
|
||||
* for images: Vectorize using selected vectorizer
|
||||
* for paths:
|
||||
|
||||
* flatten path using Cairo
|
||||
* remove self-intersections using Clipper
|
||||
* if stroke is set: process dash, then offset using Clipper
|
||||
* apply pattern fills
|
||||
* clip to clip-path
|
||||
* remove holes using Clipper
|
||||
|
||||
* for KiCAD S-Expression export: vector-composite results using CavalierContours: subtract each clear output primitive
|
||||
from all previous dark output primitives
|
||||
|
||||
Gerbolyze image vectorization
|
||||
-----------------------------
|
||||
|
||||
Gerbolyze has two built-in strategies to translate pixel images into vector images. One is its built-in halftone
|
||||
processor that tries to approximate grayscale. The other is its built-in binary vectorizer that traces contours in
|
||||
black-and-white images. Below are examples for the four options.
|
||||
|
||||
The vectorizers can be used in isolation through ``svg-flatten`` with either an SVG input that contains an image or a
|
||||
PNG/JPG input.
|
||||
|
||||
The vectorizer can be controlled globally using the ``--vectorizer`` flag in both ``gerbolyze`` and ``svg-flatten``. It
|
||||
can also be set on a per-image basis in both using ``--vectorizer-map [image svg id]=[option]["," ...]``.
|
||||
|
||||
.. for f in vec_*.png; convert -background white -gravity center $f -resize 500x500 -extent 500x500 (basename -s .png $f)-square.png; end
|
||||
.. for vec in hexgrid square poisson contours; convert vec_"$vec"_whole-square.png vec_"$vec"_detail-square.png -background transparent -splice 25x0+0+0 +append -chop 25x0+0+0 vec_"$vec"_composited.png; end
|
||||
|
||||
``--vectorizer poisson-disc`` (the default)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: pics/vec_poisson_composited.png
|
||||
|
||||
``--vectorizer hex-grid``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: pics/vec_hexgrid_composited.png
|
||||
|
||||
``--vectorizer square-grid``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: pics/vec_square_composited.png
|
||||
|
||||
``--vectorizer binary-contours``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. image:: pics/vec_contours_composited.png
|
||||
|
||||
The binary contours vectorizer requires a black-and-white binary input image. As you can see, like every bitmap tracer
|
||||
it will produce some artifacts. For artistic input this is usually not too bad as long as the input data is
|
||||
high-resolution. Antialiased edges in the input image are not only OK, they may even help with an accurate
|
||||
vectorization.
|
||||
|
||||
GIMP halftone preprocessing guide
|
||||
---------------------------------
|
||||
|
||||
Gerbolyze has its own built-in halftone processor, but you can also use the high-quality "newsprint" filter built into
|
||||
GIMP_ instead if you like. This section will guide you through this. The PNG you get out of this can then be fed into
|
||||
gerbolyze using ``--vectorizer binary-contours``.
|
||||
|
||||
1 Import a render of the board generated using ``gerbolyze render``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -152,6 +274,28 @@ Gallery
|
|||
|
||||
.. image:: https://raw.githubusercontent.com/jaseg/gerbolyze/master/sample3.jpg
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
SVG raster features
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Currently, SVG masks and filters are not supported. Though SVG is marketed as a "vector graphics format", these two
|
||||
features are really raster primitives that all SVG viewers perform at the pixel level after rasterization. Since
|
||||
supporting these would likely not end up looking like what you want, it is not a planned feature. If you need masks or
|
||||
filters, simply export the relevant parts of the SVG as a PNG then include that in your template.
|
||||
|
||||
Gerber pass-through
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Since gerbolyze has to composite your input gerbers with its own output, it has to fully parse and re-serialize them.
|
||||
gerbolyze uses pcb-tools_ and pcb-tools-extension_ for all its gerber parsing needs. Both seem well-written, but likely
|
||||
not free of bugs. This means that in rare cases information may get lost during this round trip. Thus, *always* check
|
||||
the output files for errors before submitting them to production.
|
||||
|
||||
Gerbolyze is provided without any warranty, but still please open an issue or `send me an email
|
||||
<mailto:gerbolyze@jaseg.de>`__ if you find any errors or inconsistencies.
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
|
@ -164,3 +308,8 @@ many people as possible and I wouldn't want the license to be a hurdle to anyone
|
|||
board house just integrating a fork into their webpage without providing their changes back upstream, and I want to
|
||||
avoid that so the default license is still AGPL.
|
||||
|
||||
.. _usvg: https://github.com/RazrFalcon/resvg
|
||||
.. _Inkscape: https://inkscape.org/
|
||||
.. _pcb-tools: https://github.com/curtacircuitos/pcb-tools
|
||||
.. _pcb-tools-extension: https://github.com/opiopan/pcb-tools-extension
|
||||
.. _GIMP: https://gimp.org/
|
||||
|
|
|
@ -96,6 +96,7 @@ def paste(input_gerbers, output_gerbers, top, bottom,
|
|||
outfile = tmpdir / 'dilated-{layer}-{amount}.gbr'
|
||||
dilate_gerber(layers, layer, amount, bbox, tmpdir, outfile, units)
|
||||
gbr = gerberex.read(str(outfile))
|
||||
gbr.offset(bounds[0][0], bounds[1][0])
|
||||
return gbr
|
||||
|
||||
for layer, input_files in layers.items():
|
||||
|
@ -121,8 +122,8 @@ def paste(input_gerbers, output_gerbers, top, bottom,
|
|||
print('compositing')
|
||||
comp = gerberex.GerberComposition()
|
||||
foo = gerberex.rs274x.GerberFile.from_gerber_file(in_grb.cam_source)
|
||||
foo.offset(-bounds[0][0], -bounds[1][0])
|
||||
comp.merge(foo)
|
||||
overlay_grb.offset(bounds[0][0], bounds[1][0])
|
||||
comp.merge(overlay_grb)
|
||||
dilations = subtract_map.get(layer, [])
|
||||
for d_layer, amount in dilations:
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 442 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 509 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 729 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 504 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 1.2 MiB |
Przed Szerokość: | Wysokość: | Rozmiar: 293 KiB Po Szerokość: | Wysokość: | Rozmiar: 293 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 246 KiB Po Szerokość: | Wysokość: | Rozmiar: 246 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 167 KiB Po Szerokość: | Wysokość: | Rozmiar: 167 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 143 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 1.2 MiB |
Po Szerokość: | Wysokość: | Rozmiar: 40 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 208 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 301 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 173 KiB |
|
@ -188,9 +188,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
} else if (fmt == "s-exp" || fmt == "sexp" || fmt == "kicad") {
|
||||
if (!args["sexp_mod_name"]) {
|
||||
cerr << "--sexp-mod-name must be given for sexp export" << endl;
|
||||
argagg::fmt_ostream fmt(cerr);
|
||||
fmt << usage.str() << argparser;
|
||||
cerr << "Error: --sexp-mod-name must be given for sexp export" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -199,9 +197,7 @@ int main(int argc, char **argv) {
|
|||
is_sexp = true;
|
||||
|
||||
} else {
|
||||
cerr << "Unknown output format \"" << fmt << "\"" << endl;
|
||||
argagg::fmt_ostream fmt(cerr);
|
||||
fmt << usage.str() << argparser;
|
||||
cerr << "Error: Unknown output format \"" << fmt << "\"" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -265,8 +261,6 @@ int main(int argc, char **argv) {
|
|||
cerr << "writing bitmap into svg" << endl;
|
||||
if (!args["size"]) {
|
||||
cerr << "Error: --size must be given when using bitmap input." << endl;
|
||||
argagg::fmt_ostream fmt(cerr);
|
||||
fmt << usage.str() << argparser;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -274,8 +268,6 @@ int main(int argc, char **argv) {
|
|||
auto pos = sz.find_first_of("x*,");
|
||||
if (pos == string::npos) {
|
||||
cerr << "Error: --size must be of form 12.34x56.78" << endl;
|
||||
argagg::fmt_ostream fmt(cerr);
|
||||
fmt << usage.str() << argparser;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -287,8 +279,6 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (width < 1 || height < 1) {
|
||||
cerr << "Error: --size must be of form 12.34x56.78 and values must be positive floating-point numbers in mm" << endl;
|
||||
argagg::fmt_ostream fmt(cerr);
|
||||
fmt << usage.str() << argparser;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
|