deploy.py auto-commit
650
projects/gerbolyze/index.html
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gerbolyze | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>Gerbolyze</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/gerbolyze/">Gerbolyze</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbolyze.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/gerbolyze/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/gerbolyze">Docs</a>
|
||||
<a href="https://pypi.org/project/gerbolyze">PyPI</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>Gerbolyze renders SVG vector and PNG/JPG raster images into existing gerber PCB manufacturing files.
|
||||
Vector data from SVG files is rendered losslessly <em>without</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>Try gerbolyze online at <a class="reference external" href="https://dyna.kokoroyukuma.de/gerboweb">https://dyna.kokoroyukuma.de/gerboweb</a></p>
|
||||
<div class="figure">
|
||||
<img alt="pics/pcbway_sample_02_small.jpg" src="pics/pcbway_sample_02_small.jpg" style="width: 800px;" />
|
||||
<p class="caption">Drawing by <a class="reference external" href="https://twitter.com/fluffy2038/status/1317231121269104640">トーコ Toko</a> converted using Gerbolyze and printed at PCBWay.</p>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>Gerbolyze is based on <a class="reference external" href="https://gitlab.com/gerbolyze/gerbonara">gerbonara</a>.</p>
|
||||
<img alt="pics/process-overview.png" src="pics/process-overview.png" style="width: 800px;" />
|
||||
<div class="contents topic" id="contents">
|
||||
<p class="topic-title">Contents</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#tl-dr-produce-high-quality-artistic-pcbs-in-three-easy-steps" id="toc-entry-1">Tl;dr: Produce high-quality artistic PCBs in three easy steps!</a></li>
|
||||
<li><a class="reference internal" href="#quick-start-installation-any-platform" id="toc-entry-2">Quick Start Installation (Any Platform)</a></li>
|
||||
<li><a class="reference internal" href="#speeding-up-gerbolyze-using-natively-built-binaries" id="toc-entry-3">Speeding up gerbolyze using natively-built binaries</a><ul>
|
||||
<li><a class="reference internal" href="#build-from-source-any-distro" id="toc-entry-4">Build from source (any distro)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#features" id="toc-entry-5">Features</a></li>
|
||||
<li><a class="reference internal" href="#algorithm-overview" id="toc-entry-6">Algorithm Overview</a></li>
|
||||
<li><a class="reference internal" href="#web-interface" id="toc-entry-7">Web interface</a></li>
|
||||
<li><a class="reference internal" href="#command-line-usage" id="toc-entry-8">Command-line usage</a><ul>
|
||||
<li><a class="reference internal" href="#gerbolyze-template" id="toc-entry-9"><tt class="docutils literal">gerbolyze template</tt></a><ul>
|
||||
<li><a class="reference internal" href="#options" id="toc-entry-10">Options:</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#gerbolyze-paste" id="toc-entry-11"><tt class="docutils literal">gerbolyze paste</tt></a><ul>
|
||||
<li><a class="reference internal" href="#options-1" id="toc-entry-12">Options:</a></li>
|
||||
<li><a class="reference internal" href="#outline-layers-1" id="toc-entry-13">Outline layers</a></li>
|
||||
<li><a class="reference internal" href="#subtraction-scripts" id="toc-entry-14">Subtraction scripts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#svg-flatten-1" id="toc-entry-15"><tt class="docutils literal"><span class="pre">svg-flatten</span></tt></a><ul>
|
||||
<li><a class="reference internal" href="#options-2" id="toc-entry-16">Options:</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#gerbolyze-image-vectorization" id="toc-entry-17">Gerbolyze image vectorization</a><ul>
|
||||
<li><a class="reference internal" href="#vectorizer-poisson-disc-the-default" id="toc-entry-18"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">poisson-disc</span></tt> (the default)</a></li>
|
||||
<li><a class="reference internal" href="#vectorizer-hex-grid" id="toc-entry-19"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">hex-grid</span></tt></a></li>
|
||||
<li><a class="reference internal" href="#vectorizer-square-grid" id="toc-entry-20"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">square-grid</span></tt></a></li>
|
||||
<li><a class="reference internal" href="#vectorizer-binary-contours" id="toc-entry-21"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">binary-contours</span></tt></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#gimp-halftone-preprocessing-guide" id="toc-entry-22">GIMP halftone preprocessing guide</a><ul>
|
||||
<li><a class="reference internal" href="#import-your-desired-artwork" id="toc-entry-23">1 Import your desired artwork</a></li>
|
||||
<li><a class="reference internal" href="#convert-the-image-to-grayscale" id="toc-entry-24">2 Convert the image to grayscale</a></li>
|
||||
<li><a class="reference internal" href="#fine-tune-the-image-s-contrast" id="toc-entry-25">3 Fine-tune the image's contrast</a></li>
|
||||
<li><a class="reference internal" href="#retouch-details" id="toc-entry-26">4 Retouch details</a></li>
|
||||
<li><a class="reference internal" href="#run-the-newsprint-filter" id="toc-entry-27">5 Run the newsprint filter</a></li>
|
||||
<li><a class="reference internal" href="#export-the-image-for-use-with-gerbolyze-vectorize" id="toc-entry-28">6 Export the image for use with <tt class="docutils literal">gerbolyze vectorize</tt></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#manufacturing-considerations" id="toc-entry-29">Manufacturing Considerations</a></li>
|
||||
<li><a class="reference internal" href="#limitations" id="toc-entry-30">Limitations</a><ul>
|
||||
<li><a class="reference internal" href="#svg-raster-features" id="toc-entry-31">SVG raster features</a></li>
|
||||
<li><a class="reference internal" href="#gerber-pass-through" id="toc-entry-32">Gerber pass-through</a></li>
|
||||
<li><a class="reference internal" href="#trace-space-design-rule-adherence" id="toc-entry-33">Trace/Space design rule adherence</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#gallery" id="toc-entry-34">Gallery</a></li>
|
||||
<li><a class="reference internal" href="#licensing" id="toc-entry-35">Licensing</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="tl-dr-produce-high-quality-artistic-pcbs-in-three-easy-steps">
|
||||
<h2><a class="toc-backref" href="#toc-entry-1">Tl;dr: Produce high-quality artistic PCBs in three easy steps!</a></h2>
|
||||
<p>Gerbolyze works in three steps.</p>
|
||||
<ol class="arabic">
|
||||
<li><p class="first">Generate a scale-accurate template of the finished PCB from your CAD tool's gerber output:</p>
|
||||
<pre class="code literal-block">
|
||||
<span class="lineno"></span><span class="line">$ gerbolyze template --top template_top.svg [--bottom template_bottom.svg] my_gerber_dir
|
||||
</span></pre>
|
||||
</li>
|
||||
<li><p class="first">Load the resulting template image <a class="reference external" href="https://inkscape.org/">Inkscape</a> 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.</p>
|
||||
</li>
|
||||
<li><p class="first">Vectorize the edited SVG template image drectly into the PCB's gerber files:</p>
|
||||
<pre class="code literal-block">
|
||||
<span class="lineno"></span><span class="line">$ gerbolyze paste --top template_top_edited.svg [--bottom ...] my_gerber_dir output_gerber_dir
|
||||
</span></pre>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="quick-start-installation-any-platform">
|
||||
<h2><a class="toc-backref" href="#toc-entry-2">Quick Start Installation (Any Platform)</a></h2>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>gerbolyze
|
||||
</span></pre>
|
||||
<p>To uninstall, run</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>uninstall<span class="w"> </span>gerbolyze<span class="w"> </span>gerbonara<span class="w"> </span>resvg-wasi<span class="w"> </span>svg-flatten-wasi
|
||||
</span></pre>
|
||||
<p>To update, run</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>--upgrade<span class="w"> </span>--upgrade-strategy<span class="w"> </span>eager<span class="w"> </span>gerbolyze
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="speeding-up-gerbolyze-using-natively-built-binaries">
|
||||
<h2><a class="toc-backref" href="#toc-entry-3">Speeding up gerbolyze using natively-built binaries</a></h2>
|
||||
<p>This will install gerbolyze's binary dependency resvg and gerbolyze's svg-flatten utility as pre-built cross-platform
|
||||
WASM binaries. When you first run gerbolyze, it will take some time (~30s) to link these binaries for your system. The
|
||||
output is cached, so any future run is going to be fast.</p>
|
||||
<p>WASM is slower than natively-built binaries. To speed up gerbolyze, you can natively build its two binary dependencies:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>Install resvg natively using rust's cargo package manager: <tt class="docutils literal">cargo install resvg</tt></li>
|
||||
<li>Install gerbolyze's svg-flatten utility natively. You can get pre-built binaries from gerbolyze's gitlab CI jobs <a class="reference external" href="https://gitlab.com/gerbolyze/gerbolyze/-/pipelines?scope=tags&page=1">at
|
||||
this link</a> by clicking the three dots on the
|
||||
right next to the version you want. These pre-built binaries should work on any x86_64 linux since they are
|
||||
statically linked. You can also build svg-flatten yourself by running <tt class="docutils literal">make</tt> inside the <tt class="docutils literal"><span class="pre">svg-flatten</span></tt> folder from
|
||||
a gerbolyze checkout.</li>
|
||||
</ol>
|
||||
<p>Gerbolyze will pick up these binaries when installed in your <tt class="docutils literal">$PATH</tt>. resvg is also picked up when it is installed by
|
||||
cargo in your home's <tt class="docutils literal"><span class="pre">~/.cargo</span></tt>, even if it's not in your <tt class="docutils literal">$PATH</tt>. You can override the resvg, usvg or svg-flatten
|
||||
binary that gerbolyze uses by giving it the absoulute path to a binary in the <tt class="docutils literal">$RESVG</tt>, <tt class="docutils literal">$USVG</tt> and <tt class="docutils literal">$SVG_FLATTEN</tt>
|
||||
environment variables.</p>
|
||||
<div class="section" id="build-from-source-any-distro">
|
||||
<h3><a class="toc-backref" href="#toc-entry-4">Build from source (any distro)</a></h3>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">git<span class="w"> </span>clone<span class="w"> </span>--recurse-submodules<span class="w"> </span>https://git.jaseg.de/gerbolyze.git<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nb">cd</span><span class="w"> </span>gerbolyze<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>python3<span class="w"> </span>-m<span class="w"> </span>venv<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nb">source</span><span class="w"> </span>venv/bin/activate<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>python3<span class="w"> </span>setup.py<span class="w"> </span>install
|
||||
</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="features">
|
||||
<h2><a class="toc-backref" href="#toc-entry-5">Features</a></h2>
|
||||
<p>Input on the left, output on the right.</p>
|
||||
<img alt="pics/test_svg_readme_composited.png" src="pics/test_svg_readme_composited.png" style="width: 800px;" />
|
||||
<ul class="simple">
|
||||
<li>Almost full SVG 1.1 static spec coverage (!)<ul>
|
||||
<li>Paths with beziers, self-intersections and holes</li>
|
||||
<li>Strokes, even with dashes and markers</li>
|
||||
<li>Pattern fills and strokes</li>
|
||||
<li>Transformations and nested groups</li>
|
||||
<li>Proper text rendering with support for complex text layout (e.g. Arabic)</li>
|
||||
<li><image> elements via either built-in vectorizer or built-in halftone processor</li>
|
||||
<li>(some) CSS</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Writes Gerber, SVG or KiCAD S-Expression (<tt class="docutils literal">.kicad_mod</tt>) formats</li>
|
||||
<li>Can export from top/bottom SVGs to a whole gerber layer stack at once with filename autodetection</li>
|
||||
<li>Can export SVGs to <tt class="docutils literal">.kicad_mod</tt> files like svg2mod (but with full SVG support)</li>
|
||||
<li>Beziers flattening with configurable tolerance using actual math!</li>
|
||||
<li>Polygon intersection removal</li>
|
||||
<li>Polygon hole removal (!)</li>
|
||||
<li>Optionally vector-compositing of output: convert black/white/transparent image to black/transparent image</li>
|
||||
<li>Renders SVG templates from input gerbers for accurate and easy scaling and positioning of artwork</li>
|
||||
<li>layer masking with offset (e.g. all silk within 1mm of soldermask)</li>
|
||||
<li>Can read gerbers from zip files</li>
|
||||
<li>Limited SVG support for board outline layers (no fill/region support)</li>
|
||||
<li>Dashed lines supported on board outline layers</li>
|
||||
</ul>
|
||||
<p>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 (<tt class="docutils literal"><span class="pre">svg-flatten</span></tt>
|
||||
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 <tt class="docutils literal"><path></tt> elements.</p>
|
||||
</div>
|
||||
<div class="section" id="algorithm-overview">
|
||||
<h2><a class="toc-backref" href="#toc-entry-6">Algorithm Overview</a></h2>
|
||||
<p>This is the algorithm gerbolyze uses to process a stack of gerbers.</p>
|
||||
<ul class="simple">
|
||||
<li>Map input files to semantic layers by their filenames</li>
|
||||
<li>For each layer:<ul>
|
||||
<li>load input gerber</li>
|
||||
<li>Pass mask layers through <tt class="docutils literal">gerbv</tt> for conversion to SVG</li>
|
||||
<li>Pass mask layers SVG through <tt class="docutils literal"><span class="pre">svg-flatten</span> <span class="pre">--dilate</span></tt></li>
|
||||
<li>Pass input SVG through <tt class="docutils literal"><span class="pre">svg-flatten</span> <span class="pre">--only-groups</span> [layer]</tt></li>
|
||||
<li>Overlay input gerber, mask and input svg</li>
|
||||
<li>Write result to output gerber</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>This is the algorithm svg-flatten uses to process an SVG.</p>
|
||||
<ul class="simple">
|
||||
<li>pass input SVG through <a class="reference external" href="https://github.com/RazrFalcon/resvg">usvg</a></li>
|
||||
<li>iterate depth-first through resulting SVG.<ul>
|
||||
<li>for groups: apply transforms and clip and recurse</li>
|
||||
<li>for images: Vectorize using selected vectorizer</li>
|
||||
<li>for paths:<ul>
|
||||
<li>flatten path using Cairo</li>
|
||||
<li>remove self-intersections using Clipper</li>
|
||||
<li>if stroke is set: process dash, then offset using Clipper</li>
|
||||
<li>apply pattern fills</li>
|
||||
<li>clip to clip-path</li>
|
||||
<li>remove holes using Clipper</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>for KiCAD S-Expression export: vector-composite results using CavalierContours: subtract each clear output primitive
|
||||
from all previous dark output primitives</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="web-interface">
|
||||
<h2><a class="toc-backref" href="#toc-entry-7">Web interface</a></h2>
|
||||
<p>You can try gerbolyze online at <a class="reference external" href="https://dyna.kokoroyukuma.de/gerboweb">https://dyna.kokoroyukuma.de/gerboweb</a></p>
|
||||
<p>The web interface does not expose all of gerbolyze's bells and whistles, but it allows you to simply paste a single SVG
|
||||
file on a board to try out gerbolyze. Upload your design on the web interface, then download the template for either the
|
||||
top or bottom side, and put your artwork on the appropriate layer of that template using <a class="reference external" href="https://inkscape.org/">Inkscape</a>. Finally, upload the
|
||||
modified template and let gerbolyze process your design.</p>
|
||||
</div>
|
||||
<div class="section" id="command-line-usage">
|
||||
<h2><a class="toc-backref" href="#toc-entry-8">Command-line usage</a></h2>
|
||||
<p id="command-line-usage-1">Generate SVG template from Gerber files:</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">gerbolyze<span class="w"> </span>template<span class="w"> </span><span class="o">[</span>options<span class="o">]</span><span class="w"> </span><span class="o">[</span>--top<span class="p">|</span>--bottom<span class="o">]</span><span class="w"> </span>input_dir_or.zip<span class="w"> </span>output.svg
|
||||
</span></pre>
|
||||
<p>Render design from an SVG made with the template above into a set of gerber files:</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">gerbolyze<span class="w"> </span>paste<span class="w"> </span><span class="o">[</span>options<span class="o">]</span><span class="w"> </span>artwork.svg<span class="w"> </span>input_dir_or.zip<span class="w"> </span>output_dir_or.zip
|
||||
</span></pre>
|
||||
<p>Use svg-flatten to convert an SVG file into Gerber or flattened SVG:</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">svg-flatten<span class="w"> </span><span class="o">[</span>options<span class="o">]</span><span class="w"> </span>--format<span class="w"> </span><span class="o">[</span>gerber<span class="p">|</span>svg<span class="o">]</span><span class="w"> </span><span class="o">[</span>input_file.svg<span class="o">]</span><span class="w"> </span><span class="o">[</span>output_file<span class="o">]</span>
|
||||
</span></pre>
|
||||
<p>Use svg-flatten to convert an SVG file into the given layer of a KiCAD S-Expression (<tt class="docutils literal">.kicad_mod</tt>) file:</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">svg-flatten<span class="w"> </span><span class="o">[</span>options<span class="o">]</span><span class="w"> </span>--format<span class="w"> </span>kicad<span class="w"> </span>--sexp-layer<span class="w"> </span>F.SilkS<span class="w"> </span>--sexp-mod-name<span class="w"> </span>My_Module<span class="w"> </span><span class="o">[</span>input_file.svg<span class="o">]</span><span class="w"> </span><span class="o">[</span>output_file<span class="o">]</span>
|
||||
</span></pre>
|
||||
<p>Use svg-flatten to convert an SVG file into a <tt class="docutils literal">.kicad_mod</tt> with SVG layers fed into separate KiCAD layers based on
|
||||
their IDs like the popular <tt class="docutils literal">svg2mod</tt> is doing:</p>
|
||||
<dl class="docutils">
|
||||
<dt>Note:</dt>
|
||||
<dd><p class="first">Right now, the input SVG's layers must have <em>ids</em> that match up KiCAD's s-exp layer names. Note that when you name
|
||||
a layer in Inkscape that only sets a <tt class="docutils literal">name</tt> attribute, but does not change the ID. In order to change the ID in
|
||||
Inkscape, you have to use Inkscape's "object properties" context menu function.</p>
|
||||
<p>Also note that svg-flatten expects the layer names KiCAD uses in their S-Expression format. These are <em>different</em> to
|
||||
the layer names KiCAD exposes in the UI (even though most of them match up!).</p>
|
||||
<p class="last">For your convenience, there is an SVG template with all the right layer names and IDs located next to this README.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">svg-flatten<span class="w"> </span><span class="o">[</span>options<span class="o">]</span><span class="w"> </span>--format<span class="w"> </span>kicad<span class="w"> </span>--sexp-mod-name<span class="w"> </span>My_Module<span class="w"> </span><span class="o">[</span>input_file.svg<span class="o">]</span><span class="w"> </span><span class="o">[</span>output_file<span class="o">]</span>
|
||||
</span></pre>
|
||||
<div class="section" id="gerbolyze-template">
|
||||
<h3><a class="toc-backref" href="#toc-entry-9"><tt class="docutils literal">gerbolyze template</tt></a></h3>
|
||||
<p>Usage: <tt class="docutils literal">gerbolyze template [OPTIONS] INPUT</tt></p>
|
||||
<p>Generate SVG template for gerbolyze paste from gerber files.</p>
|
||||
<p>INPUT may be a gerber file, directory of gerber files or zip file with gerber files. The output file contains a preview
|
||||
image of the input gerbers to allow you to position your artwork, as well as prepared Inkscape layers corresponding to
|
||||
each gerber layer. Simply place your artwork in this SVG template using Inkscape. Starting in v3.0, gerbolyze
|
||||
automatically keeps track of which board side (top or bottom) is contained in an SVG template.</p>
|
||||
<div class="section" id="options">
|
||||
<h4><a class="toc-backref" href="#toc-entry-10">Options:</a></h4>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal"><span class="pre">--top</span> | <span class="pre">--bottom</span></tt></dt>
|
||||
<dd>Output top or bottom side template. This affects both the preview image and the prepared Inkscape layers.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--vector</span> | <span class="pre">--raster</span></tt></dt>
|
||||
<dd>Embed preview renders into output file as SVG vector graphics instead of rendering them to PNG bitmaps. The
|
||||
resulting preview may slow down your SVG editor.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--raster-dpi</span> FLOAT</tt></dt>
|
||||
<dd>DPI for rastering preview</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--bbox</span> TEXT</tt></dt>
|
||||
<dd>Output file bounding box. Format: "w,h" to force [w] mm by [h] mm output canvas OR "x,y,w,h" to force [w] mm by [h]
|
||||
mm output canvas with its bottom left corner at the given input gerber coördinates.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="gerbolyze-paste">
|
||||
<h3><a class="toc-backref" href="#toc-entry-11"><tt class="docutils literal">gerbolyze paste</tt></a></h3>
|
||||
<p>(see <a class="reference internal" href="#vectorization">below</a>)</p>
|
||||
<p>Usage: <tt class="docutils literal">gerbolyze paste [OPTIONS] INPUT_GERBERS OVERLAY_SVG OUTPUT_GERBERS</tt></p>
|
||||
<p>Render vector data and raster images from SVG file into gerbers. The SVG input file can be generated using <tt class="docutils literal">gerbolyze
|
||||
template</tt> and contains the name and board side of each layer. Note that for board outline layers, handling slightly
|
||||
differs from other layers as PCB fabs do not support filled Gerber regions on these layers.</p>
|
||||
<div class="section" id="options-1">
|
||||
<h4><a class="toc-backref" href="#toc-entry-12">Options:</a></h4>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal"><span class="pre">--bbox</span> TEXT</tt></dt>
|
||||
<dd>Output file bounding box. Format: "w,h" to force [w] mm by [h] mm output canvas OR "x,y,w,h" to force [w] mm by [h]
|
||||
mm output canvas with its bottom left corner at the given input gerber coördinates. This <strong>must match the ``--bbox`` value given to
|
||||
template</strong>!</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--subtract</span> TEXT</tt></dt>
|
||||
<dd>Use user subtraction script from argument (see <a class="reference internal" href="#subtraction-script">below</a>)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--no-subtract</span></tt></dt>
|
||||
<dd>Disable subtraction (see <a class="reference internal" href="#subtraction-script">below</a>)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--dilate</span> FLOAT</tt></dt>
|
||||
<dd>Default dilation for subtraction operations in mm (see <a class="reference internal" href="#subtraction-script">below</a>)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--trace-space</span> FLOAT</tt></dt>
|
||||
<dd>Passed through to svg-flatten, see <a class="reference internal" href="#svg-flatten">below</a>.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--vectorizer</span> TEXT</tt></dt>
|
||||
<dd>Passed through to svg-flatten, see <a class="reference internal" href="#svg-flatten">its description below</a>. Also have a look at <a class="reference internal" href="#vectorization">the examples below</a>.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--vectorizer-map</span> TEXT</tt></dt>
|
||||
<dd>Passed through to svg-flatten, see <a class="reference internal" href="#svg-flatten">below</a>.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--exclude-groups</span> TEXT</tt></dt>
|
||||
<dd>Passed through to svg-flatten, see <a class="reference internal" href="#svg-flatten">below</a>.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="outline-layers-1">
|
||||
<span id="outline-layers"></span><h4><a class="toc-backref" href="#toc-entry-13">Outline layers</a></h4>
|
||||
<p>Outline layers require special handling since PCB fabs do not support filled G36/G37 polygons on these layers. The main
|
||||
difference between normal layers and outline layers is how strokes are handled. On outline layers, strokes are
|
||||
translated to normal Gerber draw commands (D01, D02 etc.) with an aperture set to the stroke's width instead of tracing
|
||||
them to G36/G37 filled regions. This means that on outline layers, SVG end caps and line join types do not work: All
|
||||
lines are redered with round joins and end caps.</p>
|
||||
<p>One exception from this are patterns, which work as expected for both fills and strokes with full support for joins and
|
||||
end caps.</p>
|
||||
<p>Dashed strokes are supported on outline layers and can be used to make easy mouse bites.</p>
|
||||
</div>
|
||||
<div class="section" id="subtraction-scripts">
|
||||
<span id="subtraction-script"></span><h4><a class="toc-backref" href="#toc-entry-14">Subtraction scripts</a></h4>
|
||||
<img alt="pics/subtract_example.png" src="pics/subtract_example.png" style="width: 800px;" />
|
||||
<p>Subtraction scripts tell <tt class="docutils literal">gerbolyze paste</tt> to remove an area around certain input layers to from an overlay layer.
|
||||
When a input layer is given in the subtraction script, gerbolyze will dilate (extend outwards) everything on this input
|
||||
layer and remove it from the target overlay layer. By default, Gerbolyze subtracts the mask layer from the silk layer to
|
||||
make sure there are no silk primitives that overlap bare copper, and subtracts each input layer from its corresponding
|
||||
overlay to make sure the two do not overlap. In the picture above you can see both at work: The overlay contains
|
||||
halftone primitives all over the place. The subtraction script has cut out an area around all pads (mask layer) and all
|
||||
existing silkscreen. You can turn off this behavior by passing <tt class="docutils literal"><span class="pre">--no-subtract</span></tt> or pass your own "script".</p>
|
||||
<p>The syntax of these scripts is:</p>
|
||||
<pre class="code literal-block">
|
||||
<span class="lineno"></span><span class="line">{target layer} -= {source layer} {dilation} [; ...]
|
||||
</span></pre>
|
||||
<p>The target layer must be <tt class="docutils literal"><span class="pre">out.{layer</span> name}</tt> and the source layer <tt class="docutils literal"><span class="pre">in.{layer</span> name}</tt>. The layer names are gerbolyze's
|
||||
internal layer names, i.e.: <tt class="docutils literal">paste, silk, mask, copper, outline, drill</tt></p>
|
||||
<p>The dilation value is optional, but can be a float with a leading <tt class="docutils literal">+</tt> or <tt class="docutils literal">-</tt>. If given, before subtraction the
|
||||
source layer's features will be extended by that many mm. If not given, the dilation defaults to the value given by
|
||||
<tt class="docutils literal"><span class="pre">--dilate</span></tt> if given or 0.1 mm otherwise. To disable dilation, simply pass <tt class="docutils literal">+0</tt> here.</p>
|
||||
<p>Multiple commands can be separated by semicolons <tt class="docutils literal">;</tt> or line breaks.</p>
|
||||
<p>The default subtraction script is:</p>
|
||||
<pre class="code literal-block">
|
||||
<span class="lineno"></span><span class="line">out.silk -= in.mask</span>
|
||||
<span class="lineno"></span><span class="line">out.silk -= in.silk+0.5</span>
|
||||
<span class="lineno"></span><span class="line">out.mask -= in.mask+0.5</span>
|
||||
<span class="lineno"></span><span class="line">out.copper -= in.copper+0.5
|
||||
</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="svg-flatten-1">
|
||||
<span id="svg-flatten"></span><h3><a class="toc-backref" href="#toc-entry-15"><tt class="docutils literal"><span class="pre">svg-flatten</span></tt></a></h3>
|
||||
<p>Usage: <tt class="docutils literal"><span class="pre">svg-flatten</span> <span class="pre">[OPTIONS]...</span> [INPUT_FILE] [OUTPUT_FILE]</tt></p>
|
||||
<p>Specify <tt class="docutils literal">-</tt> for stdin/stdout.</p>
|
||||
<div class="section" id="options-2">
|
||||
<h4><a class="toc-backref" href="#toc-entry-16">Options:</a></h4>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal"><span class="pre">-h,</span> <span class="pre">--help</span></tt></dt>
|
||||
<dd>Print help and exit</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-v,</span> <span class="pre">--version</span></tt></dt>
|
||||
<dd>Print version and exit</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-o,</span> <span class="pre">--format</span></tt></dt>
|
||||
<dd>Output format. Supported: gerber, gerber-outline (for board outline layers), svg, s-exp (KiCAD S-Expression)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-p,</span> <span class="pre">--precision</span></tt></dt>
|
||||
<dd>Number of decimal places use for exported coordinates (gerber: 1-9, SVG: >=0). Note that not all gerber viewers are
|
||||
happy with too many digits. 5 or 6 is a reasonable choice.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--clear-color</span></tt></dt>
|
||||
<dd>SVG color to use in SVG output for "clear" areas (default: white)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--dark-color</span></tt></dt>
|
||||
<dd>SVG color to use in SVG output for "dark" areas (default: black)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-f,</span> <span class="pre">--flip-gerber-polarity</span></tt></dt>
|
||||
<dd>Flip polarity of all output gerber primitives for --format gerber.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-d,</span> <span class="pre">--trace-space</span></tt></dt>
|
||||
<dd>Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--no-header</span></tt></dt>
|
||||
<dd>Do not export output format header/footer, only export the primitives themselves</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--flatten</span></tt></dt>
|
||||
<dd>Flatten output so it only consists of non-overlapping white polygons. This perform composition at the vector level.
|
||||
Potentially slow. This defaults to on when using KiCAD S-Exp export because KiCAD does not know polarity or colors.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--no-flatten</span></tt></dt>
|
||||
<dd>Disable automatic flattening for KiCAD S-Exp export</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--dilate</span></tt></dt>
|
||||
<dd>Dilate output gerber primitives by this amount in mm. Used for masking out other layers.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-g,</span> <span class="pre">--only-groups</span></tt></dt>
|
||||
<dd>Comma-separated list of group IDs to export.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-b,</span> <span class="pre">--vectorizer</span></tt></dt>
|
||||
<dd>Vectorizer to use for bitmap images. One of poisson-disc (default), hex-grid, square-grid, binary-contours,
|
||||
dev-null. Have a look at <a class="reference internal" href="#vectorization">the examples below</a>.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--vectorizer-map</span></tt></dt>
|
||||
<dd><p class="first">Map from image element id to vectorizer. Overrides --vectorizer. Format: id1=vectorizer,id2=vectorizer,...</p>
|
||||
<p class="last">You can use this to set a certain vectorizer for specific images, e.g. if you want to use both halftone
|
||||
vectorization and contour tracing in the same SVG. Note that you can set an <tt class="docutils literal"><image></tt> element's SVG ID from within
|
||||
Inkscape though the context menu's Object Properties tool.</p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--force-svg</span></tt></dt>
|
||||
<dd>Force SVG input irrespective of file name</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--force-png</span></tt></dt>
|
||||
<dd>Force bitmap graphics input irrespective of file name</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-s,</span> <span class="pre">--size</span></tt></dt>
|
||||
<dd>Bitmap mode only: Physical size of output image in mm. Format: 12.34x56.78</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--sexp-mod-name</span></tt></dt>
|
||||
<dd>Module name for KiCAD S-Exp output. This is a mandatory argument if using S-Exp output.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--sexp-layer</span></tt></dt>
|
||||
<dd>Layer for KiCAD S-Exp output. Defaults to auto-detect layers from SVG layer/top-level group IDs. If given, SVG
|
||||
groups and layers are completely ignored and everything is simply vectorized into this layer, though you cna still
|
||||
use <tt class="docutils literal"><span class="pre">-g</span></tt> for group selection.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-a,</span> <span class="pre">--preserve-aspect-ratio</span></tt></dt>
|
||||
<dd>Bitmap mode only: Preserve aspect ratio of image. Allowed values are meet, slice. Can also parse full SVG
|
||||
preserveAspectRatio syntax.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--no-usvg</span></tt></dt>
|
||||
<dd>Do not preprocess input using usvg (do not use unless you know <em>exactly</em> what you're doing)</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--usvg-dpi</span></tt></dt>
|
||||
<dd>Passed through to usvg's --dpi, in case the input file has different ideas of DPI than usvg has.</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">--scale</span></tt></dt>
|
||||
<dd>Scale input svg lengths by this factor (-o gerber only).</dd>
|
||||
<dt><tt class="docutils literal"><span class="pre">-e,</span> <span class="pre">--exclude-groups</span></tt></dt>
|
||||
<dd>Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="gerbolyze-image-vectorization">
|
||||
<span id="vectorization"></span><h2><a class="toc-backref" href="#toc-entry-17">Gerbolyze image vectorization</a></h2>
|
||||
<p>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.</p>
|
||||
<p>The vectorizers can be used in isolation through <tt class="docutils literal"><span class="pre">svg-flatten</span></tt> with either an SVG input that contains an image or a
|
||||
PNG/JPG input.</p>
|
||||
<p>The vectorizer can be controlled globally using the <tt class="docutils literal"><span class="pre">--vectorizer</span></tt> flag in both <tt class="docutils literal">gerbolyze</tt> and <tt class="docutils literal"><span class="pre">svg-flatten</span></tt>. It
|
||||
can also be set on a per-image basis in both using <tt class="docutils literal"><span class="pre">--vectorizer-map</span> [image svg <span class="pre">id]=[option][","</span> <span class="pre">...]</span></tt>.</p>
|
||||
<!-- 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 -->
|
||||
<div class="section" id="vectorizer-poisson-disc-the-default">
|
||||
<h3><a class="toc-backref" href="#toc-entry-18"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">poisson-disc</span></tt> (the default)</a></h3>
|
||||
<img alt="pics/vec_poisson_composited.png" src="pics/vec_poisson_composited.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="vectorizer-hex-grid">
|
||||
<h3><a class="toc-backref" href="#toc-entry-19"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">hex-grid</span></tt></a></h3>
|
||||
<img alt="pics/vec_hexgrid_composited.png" src="pics/vec_hexgrid_composited.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="vectorizer-square-grid">
|
||||
<h3><a class="toc-backref" href="#toc-entry-20"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">square-grid</span></tt></a></h3>
|
||||
<img alt="pics/vec_square_composited.png" src="pics/vec_square_composited.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="vectorizer-binary-contours">
|
||||
<h3><a class="toc-backref" href="#toc-entry-21"><tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">binary-contours</span></tt></a></h3>
|
||||
<img alt="pics/vec_contours_composited.png" src="pics/vec_contours_composited.png" style="width: 800px;" />
|
||||
<p>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.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="gimp-halftone-preprocessing-guide">
|
||||
<h2><a class="toc-backref" href="#toc-entry-22">GIMP halftone preprocessing guide</a></h2>
|
||||
<p>Gerbolyze has its own built-in halftone processor, but you can also use the high-quality "newsprint" filter built into
|
||||
<a class="reference external" href="https://gimp.org/">GIMP</a> 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 <tt class="docutils literal"><span class="pre">--vectorizer</span> <span class="pre">binary-contours</span></tt>.</p>
|
||||
<div class="section" id="import-your-desired-artwork">
|
||||
<h3><a class="toc-backref" href="#toc-entry-23">1 Import your desired artwork</a></h3>
|
||||
<p>Though anime or manga pictures are highly recommended, you can use any image including photographs. Be careful to select
|
||||
a picture with comparatively low detail that remains recognizable at very low resolution. While working on a screen this
|
||||
is hard to vizualize, but the grain resulting from the low resolution of a PCB's silkscreen is quite coarse.</p>
|
||||
<img alt="screenshots/02import02.png" src="screenshots/02import02.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="convert-the-image-to-grayscale">
|
||||
<h3><a class="toc-backref" href="#toc-entry-24">2 Convert the image to grayscale</a></h3>
|
||||
<img alt="screenshots/06grayscale.png" src="screenshots/06grayscale.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="fine-tune-the-image-s-contrast">
|
||||
<h3><a class="toc-backref" href="#toc-entry-25">3 Fine-tune the image's contrast</a></h3>
|
||||
<p>To look well on the PCB, contrast is critical. If your source image is in color, you may have lost some contrast during
|
||||
grayscale conversion. Now is the time to retouch that using the GIMP's color curve tool.</p>
|
||||
<p>When using the GIMP's newsprint filter, bright grays close to white and dark grays close to black will cause very small
|
||||
dots that might be beyond your PCB manufacturer's maximum resolution. To control this case, add small steps at the ends
|
||||
of the grayscale value curve as shown (exaggerated) in the picture below. These steps saturate very bright grays to
|
||||
white and very dark grays to black while preserving the values in the middle.</p>
|
||||
<img alt="screenshots/08curve_cut.png" src="screenshots/08curve_cut.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="retouch-details">
|
||||
<h3><a class="toc-backref" href="#toc-entry-26">4 Retouch details</a></h3>
|
||||
<p>Therer might be small details that don't look right yet, such as the image's background color or small highlights that
|
||||
merge into the background now. You can manually change the color of any detail now using the GIMP's flood-fill tool.</p>
|
||||
<p>If you don't want the image's background to show up on the final PCB at all, just make it black.</p>
|
||||
<p>Particularly on low-resolution source images it may make sense to apply a blur with a radius similar to the following
|
||||
newsprint filter's cell size (10px) to smooth out the dot pattern generated by the newsprint filter.</p>
|
||||
<img alt="screenshots/09retouch.png" src="screenshots/09retouch.png" style="width: 800px;" />
|
||||
<p>In the following example, I retouched the highlights in the hair of the character in the picture to make them completely
|
||||
white instead of light-gray, so they still stand out nicely in the finished picture.</p>
|
||||
<img alt="screenshots/10retouched.png" src="screenshots/10retouched.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="run-the-newsprint-filter">
|
||||
<h3><a class="toc-backref" href="#toc-entry-27">5 Run the newsprint filter</a></h3>
|
||||
<p>Now, run the GIMP's newsprint filter, under filters, distorts, newsprint.</p>
|
||||
<p>The first important settings is the spot size, which should be larger than your PCB's minimum detail size (about 10px
|
||||
with <tt class="docutils literal">gerbolyze render</tt> default settings for good-quality silkscreen). In general the cheap and fast standard option of chinese PCB houses will require a larger detail size, but when you order specialty options like large size, 4-layer or non-green color along with a longer turnaround time you'll get much better-quality silk screen.</p>
|
||||
<p>The second important setting is oversampling, which should be set to four or slightly higher. This improves the result
|
||||
of the edge reconstruction of <tt class="docutils literal">gerbolyze vectorize</tt>.</p>
|
||||
<img alt="screenshots/11newsprint.png" src="screenshots/11newsprint.png" style="width: 800px;" />
|
||||
<p>The following are examples on the detail resulting from the newsprint filter.</p>
|
||||
<img alt="screenshots/12newsprint.png" src="screenshots/12newsprint.png" style="width: 800px;" />
|
||||
</div>
|
||||
<div class="section" id="export-the-image-for-use-with-gerbolyze-vectorize">
|
||||
<h3><a class="toc-backref" href="#toc-entry-28">6 Export the image for use with <tt class="docutils literal">gerbolyze vectorize</tt></a></h3>
|
||||
<p>Simply export the image as a PNG file. Below are some pictures of the output <tt class="docutils literal">gerbolyze vectorize</tt> produced for this
|
||||
example.</p>
|
||||
<img alt="screenshots/14result_cut.png" src="screenshots/14result_cut.png" style="width: 800px;" />
|
||||
<img alt="screenshots/15result_cut.png" src="screenshots/15result_cut.png" style="width: 800px;" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="manufacturing-considerations">
|
||||
<h2><a class="toc-backref" href="#toc-entry-29">Manufacturing Considerations</a></h2>
|
||||
<p>The main consideration when designing artwork for PCB processes is the processes' trace/space design rule. The two
|
||||
things you can do here is one, to be creative with graphical parts of the design and avoid extremely narrow lines,
|
||||
wedges or other thin features that will not come out well. Number two is to keep detail in raster images several times
|
||||
larger than the manufacturing processes native capability. For example, to target a trace/space design rule of 100 µm,
|
||||
the smallest detail in embedded raster graphics should not be much below 1mm.</p>
|
||||
<p>Gerbolyze's halftone vectorizers have built-in support for trace/space design rules. While they can still produce small
|
||||
artifacts that violate these rules, their output should be close enough to satifsy board houses and close enough for the
|
||||
result to look good. The way gerbolyze does this is to clip the halftone cell's values to zero whenevery they get too
|
||||
small, and to forcefully split or merge two neighboring cells when they get too close. While this process introduces
|
||||
slight steps at the top and bottom of grayscale response, for most inputs these are not noticeable.</p>
|
||||
<p>On the other hand, for SVG vector elements as well as for traced raster images, Gerbolyze cannot help with these design
|
||||
rules. There is no heuristic that would allow Gerbolyze to non-destructively "fix" a design here, so all that's on the
|
||||
roadmap here is to eventually include a gerber-level design rule checker.</p>
|
||||
<p>As far as board houses go, I have made good experiences with the popular Chinese board houses. In my experience, JLC
|
||||
will just produce whatever you send them with little fucks being given about design rule adherence or validity of the
|
||||
input gerbers. This is great if you just want artistic circuit boards without much of a hassle, and you don't care if
|
||||
they come out exactly as you imagined. The worst I've had happen was when an older version of gerbolyze generated
|
||||
polygons with holes assuming standard fill-rule processing. The in the board house's online gerber viewer things looked
|
||||
fine, and neither did they complain during file review. However, the resulting boards looked completely wrong because
|
||||
all the dark halftones were missing.</p>
|
||||
<p>PCBWay on the other hand has a much more rigurous file review process. They <em>will</em> complain when you throw
|
||||
illegal garbage gerbers at them, and they will helpfully guide you through your design rule violations. In this way you
|
||||
get much more of a professional service from them and for designs that have to be functional their higher level of
|
||||
scrutiny definitely is a good thing. For the design you saw in the first picture in this article, I ended up begging
|
||||
them to just plot my files if it doesn't physically break their machines and to their credit, while they seemed unhappy
|
||||
about it they did it and the result looks absolutely stunning.</p>
|
||||
<p>PCBWay is a bit more expensive on their lowest-end offering than JLC, but I found that for anything else (large boards,
|
||||
multi-layer, gold plating etc.) their prices match. PCBWay offers a much broader range of manufacturing options such as
|
||||
flexible circuit boards, multi-layer boards, thick or thin substrates and high-temperature substrates.</p>
|
||||
<p>When in doubt about how your design is going to come out on the board, do not hesitate to contact your board house. Most
|
||||
of the end customer-facing online PCB services have a number of different factories that do a number of different
|
||||
fabrication processes for them depending on order parameters. Places like PCBWay have exceptional quality control and
|
||||
good customer service, but that is mostly focused on the technical aspects of the PCB. If you rely on visual aspects
|
||||
like silkscreen uniformity or solder mask color that is a strong no concern to everyone else in the electronics
|
||||
industry, you may find significant variations between manufacturers or even between orders with the same manufacturer
|
||||
and you may encounter challenges communicating your requirements.</p>
|
||||
</div>
|
||||
<div class="section" id="limitations">
|
||||
<h2><a class="toc-backref" href="#toc-entry-30">Limitations</a></h2>
|
||||
<div class="section" id="svg-raster-features">
|
||||
<h3><a class="toc-backref" href="#toc-entry-31">SVG raster features</a></h3>
|
||||
<p>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.</p>
|
||||
</div>
|
||||
<div class="section" id="gerber-pass-through">
|
||||
<h3><a class="toc-backref" href="#toc-entry-32">Gerber pass-through</a></h3>
|
||||
<p>Since gerbolyze has to composite your input gerbers with its own output, it has to fully parse and re-serialize them.
|
||||
gerbolyze <a class="reference external" href="https://gitlab.com/gerbolyze/gerbonara">gerbonara</a> for all its gerber parsing needs. Thus, gerbonara will interpret your gerbers and output will be in
|
||||
gerbonara's gerber "dialect". If you find a corner case where this does not work and the output looks wrong, please file
|
||||
a bug report with an example file on the <a class="reference external" href="https://gitlab.com/gerbolyze/gerbonara">gerbonara</a> bug tracker. <em>Always</em> check the output files for errors before
|
||||
submitting them to production.</p>
|
||||
<p>Gerbolyze is provided without any warranty, but still please open an issue or <a class="reference external" href="mailto:gerbolyze@jaseg.de">send me an email</a> if you find any errors or inconsistencies.</p>
|
||||
</div>
|
||||
<div class="section" id="trace-space-design-rule-adherence">
|
||||
<h3><a class="toc-backref" href="#toc-entry-33">Trace/Space design rule adherence</a></h3>
|
||||
<p>While the grayscale halftone vectorizers do a reasonable job adhering to a given trace/space design rule, they can still
|
||||
produce small parts of output that violate it. For the contour vectorizer as well as for all SVG primitives, you are
|
||||
responsible for adhering to design rules yourself as there is no algorithm that gerboyze could use to "fix" its input.</p>
|
||||
<p>A design rule checker is planned as a future addition to gerbolyze, but is not yet part of it. If in doubt, talk to your
|
||||
fab and consider doing a test run of your design before ordering assembled boards ;)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="gallery">
|
||||
<h2><a class="toc-backref" href="#toc-entry-34">Gallery</a></h2>
|
||||
<img alt="pics/sample3.jpg" src="pics/sample3.jpg" style="width: 400px;" />
|
||||
<p>For a demonstration of <tt class="docutils literal">gerbolyze convert</tt>, check out the <a class="reference external" href="https://dyna.kokoroyukuma.de/protos/">Gerbolyze Protoboard Index</a>, where you can download gerber
|
||||
files for over 7.000 SMD and THT protoboard layouts.</p>
|
||||
</div>
|
||||
<div class="section" id="licensing">
|
||||
<h2><a class="toc-backref" href="#toc-entry-35">Licensing</a></h2>
|
||||
<p>This tool is licensed under the rather radical AGPLv3 license. Briefly, this means that you have to provide users of a
|
||||
webapp using this tool in the backend with this tool's source.</p>
|
||||
<p>I get that some people have issues with the AGPL. In case this license prevents you from using this software, please
|
||||
send me <a class="reference external" href="mailto:agpl.sucks@jaseg.de">an email</a> and I can grant you an exception. I want this software to be useful to as
|
||||
many people as possible and I wouldn't want the license to be a hurdle to anyone. OTOH I see a danger of some cheap
|
||||
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.</p>
|
||||
</div>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
projects/gerbolyze/pics/ex-flattening.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
projects/gerbolyze/pics/ex-intersections.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
projects/gerbolyze/pics/ex-strokes.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
projects/gerbolyze/pics/ex-svg-joins.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
projects/gerbolyze/pics/ex-svg-strokes.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
projects/gerbolyze/pics/ex-svg-winding.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
projects/gerbolyze/pics/fr4_comparison2.jpg
Normal file
|
After Width: | Height: | Size: 266 KiB |
BIN
projects/gerbolyze/pics/pcbway_sample_01_small.jpg
Normal file
|
After Width: | Height: | Size: 442 KiB |
BIN
projects/gerbolyze/pics/pcbway_sample_02_small.jpg
Normal file
|
After Width: | Height: | Size: 509 KiB |
BIN
projects/gerbolyze/pics/pcbway_sample_03_small.jpg
Normal file
|
After Width: | Height: | Size: 729 KiB |
BIN
projects/gerbolyze/pics/process-overview.png
Normal file
|
After Width: | Height: | Size: 504 KiB |
7230
projects/gerbolyze/pics/process-overview.svg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
projects/gerbolyze/pics/sample1.jpg
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
projects/gerbolyze/pics/sample2.jpg
Normal file
|
After Width: | Height: | Size: 246 KiB |
BIN
projects/gerbolyze/pics/sample3.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
projects/gerbolyze/pics/subtract_example.png
Normal file
|
After Width: | Height: | Size: 232 KiB |
515
projects/gerbolyze/pics/test_svg_readme.svg
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
projects/gerbolyze/pics/test_svg_readme_composited.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
projects/gerbolyze/pics/vec_contours_composited.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
projects/gerbolyze/pics/vec_hexgrid_composited.png
Normal file
|
After Width: | Height: | Size: 243 KiB |
BIN
projects/gerbolyze/pics/vec_poisson_composited.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
projects/gerbolyze/pics/vec_square_composited.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
projects/gerbolyze/screenshots/01import01.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
projects/gerbolyze/screenshots/02import02.png
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
projects/gerbolyze/screenshots/03paste.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
projects/gerbolyze/screenshots/04scale_cut.png
Normal file
|
After Width: | Height: | Size: 380 KiB |
BIN
projects/gerbolyze/screenshots/05position.png
Normal file
|
After Width: | Height: | Size: 365 KiB |
BIN
projects/gerbolyze/screenshots/06grayscale.png
Normal file
|
After Width: | Height: | Size: 307 KiB |
BIN
projects/gerbolyze/screenshots/07curve_settings.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
projects/gerbolyze/screenshots/08curve_cut.png
Normal file
|
After Width: | Height: | Size: 280 KiB |
BIN
projects/gerbolyze/screenshots/09retouch.png
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
projects/gerbolyze/screenshots/10retouched.png
Normal file
|
After Width: | Height: | Size: 310 KiB |
BIN
projects/gerbolyze/screenshots/11newsprint.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
projects/gerbolyze/screenshots/11newsprint_settings.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
projects/gerbolyze/screenshots/12newsprint.png
Normal file
|
After Width: | Height: | Size: 568 KiB |
BIN
projects/gerbolyze/screenshots/13newsprint.png
Normal file
|
After Width: | Height: | Size: 503 KiB |
BIN
projects/gerbolyze/screenshots/14newsprint.png
Normal file
|
After Width: | Height: | Size: 334 KiB |
BIN
projects/gerbolyze/screenshots/14result_cut.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
projects/gerbolyze/screenshots/15result_cut.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
projects/gerbolyze/screenshots/16result_cut.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
projects/gerbolyze/screenshots/17caveat_cut.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
projects/gerbolyze/screenshots/18caveat_cut.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
165
projects/gerbonara/index.html
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gerbonara | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>Gerbonara</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/gerbonara/">Gerbonara</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbonara.git">Sources</a>
|
||||
<a href="https://gitlab.com/gerbolyze/gerbonara/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/gerbonara">Docs</a>
|
||||
<a href="https://pypi.org/project/gerbonara">PyPI</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>Gerbonara is a library to read, modify and write PCB manufacturing files such as Gerber, Excellon and IPC-356 through a
|
||||
pythonic API. Gerbonara can open a folder of manufacturing files, and parse file names and metadata to figure out which
|
||||
file contains what. Gerbonara is tested using an extensive library of real-world example files from CAD tools including
|
||||
KiCAD, Altium, Eagle, Allegro, gEDA, Fritzing, Siemens/Mentor Graphics PADS, and Target3001!.</p>
|
||||
<p>Gerbonara's API is built on two principles:</p>
|
||||
<dl class="docutils">
|
||||
<dt><strong>Meaningful, object-oriented API</strong></dt>
|
||||
<dd>Gerbonara abstracts away the details of the underlying file format such as tool indices, coordinate notation and
|
||||
graphical state, and presents meaningful "graphical objects" such as a <cite>primitives.Line</cite>,
|
||||
<cite>primitives.Arc</cite>, or <cite>Region</cite> through its API. These objects can be easily created,
|
||||
manipulated or deleted from code without breaking anything else. You can even copy graphical objects between files,
|
||||
and Gerbonara will automatically convert coordinate format, units etc. for you. <cite>GerberFile</cite> and
|
||||
<cite>ExcellonFile</cite> use the same types of <cite>graphic objects <object-api></cite>, so objects can be directly
|
||||
copied between file types without conversion.</dd>
|
||||
<dt><strong>Unit-safety</strong></dt>
|
||||
<dd>Gerbonara embeds physical <cite>LengthUnit</cite> information in all objects. The high-level API such as
|
||||
<cite>LayerStack.merge</cite> or <cite>GerberFile.offset</cite> accepts arguments with an explicitly given unit and
|
||||
automatically converts them as needed. Objects can be copied between <cite>GerberFile</cite> instances and unit
|
||||
conversion will be handled transparently in the background.</dd>
|
||||
</dl>
|
||||
<p>Gerbonara was started as an extensive refactoring of the <a class="reference external" href="https://github.com/opiopan/pcb-tools-extension">pcb-tools</a> and <a class="reference external" href="https://github.com/curtacircuitos/pcb-tools/issues">pcb-tools-extension</a> packages. Both of these
|
||||
have statement-based APIs, that is, they parse input files into one python object for every line in the file. This means
|
||||
that when saving files they can recreate the input file almost byte by byte, but manipulating a file by changing
|
||||
statements without breaking things is <em>hard</em>.</p>
|
||||
<p>Gerbonara powers <a class="reference external" href="https://github.com/jaseg/gerbolyze">gerbolyze</a>, a tool for converting <a class="reference external" href="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a> vector graphics files into Gerber, and embedding <a class="reference external" href="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics">SVG</a> into
|
||||
existing Gerber files exported from a normal PCB tool for artistic purposes.</p>
|
||||
<div class="section" id="features">
|
||||
<h2>Features</h2>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>File I/O
|
||||
* Gerber, Excellon (drill file), IPC-356 (netlist) read and write
|
||||
* supports file-level operations: offset, rotate, merge for all file types</li>
|
||||
<li>Modification API (<cite>GraphicObject</cite>)</li>
|
||||
<li>Rendering API (<cite>GraphicPrimitive</cite>)</li>
|
||||
<li>SVG export</li>
|
||||
<li>Full aperture macro support, including transformations (offset, rotation)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="section" id="quick-start">
|
||||
<h2>Quick Start</h2>
|
||||
<p>First, install gerbonara from PyPI using pip:</p>
|
||||
<pre class="code shell literal-block">
|
||||
<span class="lineno"></span><span class="line">pip<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>gerbonara
|
||||
</span></pre>
|
||||
<p>Then, you are ready to read and write gerber files:</p>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="kn">from</span> <span class="nn">gerbonara</span> <span class="kn">import</span> <span class="n">LayerStack</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">stack</span> <span class="o">=</span> <span class="n">LayerStack</span><span class="o">.</span><span class="n">from_directory</span><span class="p">(</span><span class="s1">'output/gerber'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">w</span><span class="p">,</span> <span class="n">h</span> <span class="o">=</span> <span class="n">stack</span><span class="o">.</span><span class="n">outline</span><span class="o">.</span><span class="n">size</span><span class="p">(</span><span class="s1">'mm'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">'Board size is </span><span class="si">{</span><span class="n">w</span><span class="si">:</span><span class="s1">.1f</span><span class="si">}</span><span class="s1"> mm x </span><span class="si">{</span><span class="n">h</span><span class="si">:</span><span class="s1">.1f</span><span class="si">}</span><span class="s1"> mm'</span><span class="p">)</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="command-line-interface">
|
||||
<h2>Command-Line Interface</h2>
|
||||
<p>Gerbonara comes with a <cite>built-in command-line interface<cli-doc></cite> that has functions for analyzing, rendering,
|
||||
modifying, and merging Gerber files. To access it, use either the <tt class="docutils literal">gerbonara</tt> command that is part of the python
|
||||
package, or run <tt class="docutils literal">python <span class="pre">-m</span> gerbonara</tt> For a list of functions or help on their usage, you can use:</p>
|
||||
<pre class="code console literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>gerbonara<span class="w"> </span>--help<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="go">[...]</span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="go"></span><span class="gp">$ </span>python<span class="w"> </span>-m<span class="w"> </span>gerbonara<span class="w"> </span>render<span class="w"> </span>--help
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="development">
|
||||
<h2>Development</h2>
|
||||
<p>Gerbonara is developed on Gitlab under the gerbolyze org:</p>
|
||||
<p><a class="reference external" href="https://gitlab.com/gerbolyze/gerbonara/">https://gitlab.com/gerbolyze/gerbonara/</a></p>
|
||||
<p>A mirror of the repository can be found at:</p>
|
||||
<p><a class="reference external" href="https://git.jaseg.de/gerbonara">https://git.jaseg.de/gerbonara</a></p>
|
||||
<p>Our issue tracker is also on Gitlab:</p>
|
||||
<p><a class="reference external" href="https://gitlab.com/gerbolyze/gerbonara/-/issues">https://gitlab.com/gerbolyze/gerbonara/-/issues</a></p>
|
||||
<p>The documentation can be found at gitlab:</p>
|
||||
<p><a class="reference external" href="https://gerbolyze.gitlab.io/gerbonara/">https://gerbolyze.gitlab.io/gerbonara/</a></p>
|
||||
<p>With Gerbonara, we aim to support as many different format variants as possible. If you have a file that Gerbonara can't
|
||||
open, please file an issue on our issue tracker. Even if Gerbonara can open all your files, for regression testing we
|
||||
are very interested in example files generated by any CAD or CAM tool that is not already on the list of supported
|
||||
tools.</p>
|
||||
</div>
|
||||
<div class="section" id="supported-cad-tools">
|
||||
<h2>Supported CAD Tools</h2>
|
||||
<p>Compatibility with the output of these CAD tools is tested as part of our test suite using example files generated by
|
||||
these tools. Note that not all of these tools come with default Gerber file naming rules, so YMMV if your Gerbers use
|
||||
some non-standard naming convention.</p>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>Allegro</li>
|
||||
<li>Altium</li>
|
||||
<li>Diptrace</li>
|
||||
<li>Eagle</li>
|
||||
<li>EasyEDA</li>
|
||||
<li>Fritzing</li>
|
||||
<li>gEDA</li>
|
||||
<li>KiCAD</li>
|
||||
<li>pcb-rnd</li>
|
||||
<li>Siemens / Mentor Graphics Xpedition</li>
|
||||
<li>Siemens PADS</li>
|
||||
<li>Target 3001!</li>
|
||||
<li>Upverter</li>
|
||||
<li>Zuken CR-8000</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
163
projects/index.html
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Projects | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects" class="active">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>Projects</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li><li><a href="/projects/">Projects</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main class="cards">
|
||||
<div class="intro">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>I maintain a number of open-source projects. Most of these I started out of some personal need or interest.
|
||||
I strive to keep all of them up to date and maintained, so if you notice an issue with one of them, please
|
||||
open an issue on the project's issue tracker.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card"><h2><a href="/projects/gerbolyze/">Gerbolyze</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>Gerbolyze is a tool that allows the modification of Gerber PCB artwork with a vector graphics editor like Inkscape. Gerbolyze directly converts between SVG and Gerber, and accurately reproduces details that other tools can not.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/gerbolyze/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbolyze.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/gerbolyze/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/gerbolyze">Docs</a>
|
||||
<a href="https://pypi.org/project/gerbolyze">PyPI</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card"><h2><a href="/projects/gerbonara/">Gerbonara</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>Gerbonara is a user-friendly, powerful tool for reading, writing, modification and rendering of Gerber PCB artwork from the command line or from Python code. Gerbonara supports the Gerber dialects of all industry-standard EDA tools.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/gerbonara/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbonara.git">Sources</a>
|
||||
<a href="https://gitlab.com/gerbolyze/gerbonara/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/gerbonara">Docs</a>
|
||||
<a href="https://pypi.org/project/gerbonara">PyPI</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card"><h2><a href="/projects/lolcat-c/">lolcat-c</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>lolcat-c is a small, high-performance re-implementation of the <a class="reference external" href="https://github.com/busyloop/lolcat">lolcat</a> rainbow cat utility. lolcat-c is meant as a lolcat that you can actually use in production. It is fast, not slowing down whatever you pipe through it, and it robustly handles real-world terminal output including escape sequences.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/lolcat-c/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/lolcat.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/lolcat">Github</a>
|
||||
<a href="https://github.com/jaseg/lolcat/issues">Issues</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card"><h2><a href="/projects/python-mpv/">python-mpv</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>python-mpv is a small, ctypes-based Python library wrapping the libmpv media player library. Despite its small size and simple API, python-mpv allows advanced control over libmpv and beyond simple remote control of mpv can be used to embed mpv in OpenGL, Qt, and GTK-based Python applications.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/python-mpv/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/python-mpv.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/python-mpv/issues">Issues</a>
|
||||
<a href="https://neinseg.gitlab.io/python-mpv">Docs</a>
|
||||
<a href="https://pypi.org/project/mpv">PyPI</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card"><h2><a href="/projects/svg-flatten/">svg-flatten</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>svg-flatten is a command-line utility that performs vector occlusion and clipping on SVG files, producing a flattened SVG file without overlapping elements, without changing what the file looks like. svg-flatten is used as a part of gerbolyze.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/svg-flatten/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbolyze.git/tree/svg-flatten?h=main">Sources</a>
|
||||
<a href="https://github.com/jaseg/gerbolyze/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/svg-flatten">Docs</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card"><h2><a href="/projects/wsdiff/">wsdiff</a></h2>
|
||||
|
||||
<div class="summary">
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>wsdiff is a command-line utility that produces self-contained, syntax-highlighted, HTML-formatted diffs that support both unified and side-by-side diffs from a single source file using nothing but CSS magic.</p>
|
||||
</div>
|
||||
<a href="http://jaseg.de/projects/wsdiff/">Read more</a>
|
||||
</div>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/wsdiff.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/wsdiff/issues">Issues</a>
|
||||
<a href="https://pypi.org/project/wsdiff">PyPI</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
89
projects/index.xml
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>Projects on Home</title>
|
||||
<link>http://jaseg.de/projects/</link>
|
||||
<description>Recent content in Projects on Home</description>
|
||||
<generator>Hugo -- gohugo.io</generator>
|
||||
<language>en-us</language>
|
||||
<copyright>Jan Sebastian Götte</copyright><atom:link href="http://jaseg.de/projects/index.xml" rel="self" type="application/rss+xml" />
|
||||
<item>
|
||||
<title>Gerbolyze</title>
|
||||
<link>http://jaseg.de/projects/gerbolyze/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/gerbolyze/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>Gerbolyze is a tool that allows the modification of Gerber PCB artwork with a vector graphics editor like Inkscape. Gerbolyze directly converts between SVG and Gerber, and accurately reproduces details that other tools can not.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>Gerbonara</title>
|
||||
<link>http://jaseg.de/projects/gerbonara/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/gerbonara/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>Gerbonara is a user-friendly, powerful tool for reading, writing, modification and rendering of Gerber PCB artwork from the command line or from Python code. Gerbonara supports the Gerber dialects of all industry-standard EDA tools.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>lolcat-c</title>
|
||||
<link>http://jaseg.de/projects/lolcat-c/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/lolcat-c/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>lolcat-c is a small, high-performance re-implementation of the <a class="reference external" href="https://github.com/busyloop/lolcat">lolcat</a> rainbow cat utility. lolcat-c is meant as a lolcat that you can actually use in production. It is fast, not slowing down whatever you pipe through it, and it robustly handles real-world terminal output including escape sequences.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>python-mpv</title>
|
||||
<link>http://jaseg.de/projects/python-mpv/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/python-mpv/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>python-mpv is a small, ctypes-based Python library wrapping the libmpv media player library. Despite its small size and simple API, python-mpv allows advanced control over libmpv and beyond simple remote control of mpv can be used to embed mpv in OpenGL, Qt, and GTK-based Python applications.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>svg-flatten</title>
|
||||
<link>http://jaseg.de/projects/svg-flatten/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/svg-flatten/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>svg-flatten is a command-line utility that performs vector occlusion and clipping on SVG files, producing a flattened SVG file without overlapping elements, without changing what the file looks like. svg-flatten is used as a part of gerbolyze.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<title>wsdiff</title>
|
||||
<link>http://jaseg.de/projects/wsdiff/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
|
||||
<guid>http://jaseg.de/projects/wsdiff/</guid>
|
||||
<description><div class="document">
|
||||
|
||||
|
||||
<p>wsdiff is a command-line utility that produces self-contained, syntax-highlighted, HTML-formatted diffs that support both unified and side-by-side diffs from a single source file using nothing but CSS magic.</p>
|
||||
</div></description>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
||||
BIN
projects/lolcat-c/LOLCat-Rainbow.jpg
Normal file
|
After Width: | Height: | Size: 42 KiB |
132
projects/lolcat-c/index.html
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>lolcat-c | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>lolcat-c</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/lolcat-c/">lolcat-c</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/lolcat.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/lolcat">Github</a>
|
||||
<a href="https://github.com/jaseg/lolcat/issues">Issues</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<div class="section" id="what">
|
||||
<h2>What?</h2>
|
||||
<img alt="LOLCat-Rainbow.jpg" src="LOLCat-Rainbow.jpg" />
|
||||
</div>
|
||||
<div class="section" id="screenshot">
|
||||
<h2>Screenshot</h2>
|
||||
<img alt="screenshot.png" src="screenshot.png" />
|
||||
<img alt="sl.gif" src="sl.gif" />
|
||||
</div>
|
||||
<div class="section" id="installation">
|
||||
<h2>Installation</h2>
|
||||
<div class="section" id="archlinux">
|
||||
<h3>Archlinux</h3>
|
||||
<p>There's an <a class="reference external" href="https://aur.archlinux.org/packages/c-lolcat">AUR package</a>:</p>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://aur.archlinux.org/packages/c-lolcat<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>c-lolcat<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>$<span class="w"> </span>makepkg<span class="w"> </span>-csi
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="fedora">
|
||||
<h3>Fedora</h3>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>dnf<span class="w"> </span>install<span class="w"> </span>lolcat
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="ubuntu-snap">
|
||||
<h3>Ubuntu (Snap)</h3>
|
||||
<p>See <a class="reference external" href="https://blog.simos.info/how-to-make-a-snap-package-for-lolcat-with-snapcraft-on-ubuntu/">this awesome blog post by a kind person from the internet</a>:</p>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>snap<span class="w"> </span>install<span class="w"> </span>lolcat-c
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="mac">
|
||||
<h3>Mac</h3>
|
||||
<p>Build loclcat with:</p>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>make<span class="w"> </span>lolcat
|
||||
</span></pre>
|
||||
<p>...and put the resulting binary at a place of your choice.</p>
|
||||
</div>
|
||||
<div class="section" id="others">
|
||||
<h3>Others</h3>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>make<span class="w"> </span><span class="o">&&</span><span class="w"> </span>sudo<span class="w"> </span>make<span class="w"> </span>install
|
||||
</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="why">
|
||||
<h2>Why?</h2>
|
||||
<p>This <cite>lolcat</cite> clone is an attempt to reduce the world's carbon dioxide emissions by optimizing inefficient code. It's
|
||||
>10x as fast and <0.1% as large as the original one.</p>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">newton~/d/lolcat<span class="w"> </span><<span class="m">3</span><span class="w"> </span>dmesg>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>newton~/d/lolcat<span class="w"> </span><<span class="m">3</span><span class="w"> </span><span class="nb">time</span><span class="w"> </span>upstream/bin/lolcat<span class="w"> </span>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="m">13</span>.51user<span class="w"> </span><span class="m">1</span>.34system<span class="w"> </span><span class="m">0</span>:15.99elapsed<span class="w"> </span><span class="m">92</span>%CPU<span class="w"> </span><span class="o">(</span>0avgtext+0avgdata<span class="w"> </span>10864maxresident<span class="o">)</span>k<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>0inputs+0outputs<span class="w"> </span><span class="o">(</span>0major+1716minor<span class="o">)</span>pagefaults<span class="w"> </span>0swaps<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>newton~/d/lolcat<span class="w"> </span><<span class="m">3</span><span class="w"> </span><span class="nb">time</span><span class="w"> </span>./lolcat<span class="w"> </span>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="m">0</span>.02user<span class="w"> </span><span class="m">0</span>.00system<span class="w"> </span><span class="m">0</span>:00.09elapsed<span class="w"> </span><span class="m">34</span>%CPU<span class="w"> </span><span class="o">(</span>0avgtext+0avgdata<span class="w"> </span>1936maxresident<span class="o">)</span>k<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>0inputs+0outputs<span class="w"> </span><span class="o">(</span>0major+117minor<span class="o">)</span>pagefaults<span class="w"> </span>0swaps
|
||||
</span></pre>
|
||||
<p>Bonus comparison with <a class="reference external" href="https://github.com/tehmaze/lolcat/">python-lolcat</a>:</p>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">newton~/d/lolcat<span class="w"> </span><<span class="m">3</span><span class="w"> </span>dmesg>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>$<span class="w"> </span><span class="nb">time</span><span class="w"> </span>python-lolcat<span class="w"> </span>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="m">12</span>.27user<span class="w"> </span><span class="m">0</span>.00system<span class="w"> </span><span class="m">0</span>:12.29elapsed<span class="w"> </span><span class="m">99</span>%CPU<span class="w"> </span><span class="o">(</span>0avgtext+0avgdata<span class="w"> </span>11484maxresident<span class="o">)</span>k<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>0inputs+0outputs<span class="w"> </span><span class="o">(</span>0major+1627minor<span class="o">)</span>pagefaults<span class="w"> </span>0swaps<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>$<span class="w"> </span><span class="nb">time</span><span class="w"> </span>c-lolcat<span class="w"> </span>foo<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="m">0</span>.29user<span class="w"> </span><span class="m">0</span>.00system<span class="w"> </span><span class="m">0</span>:00.30elapsed<span class="w"> </span><span class="m">98</span>%CPU<span class="w"> </span><span class="o">(</span>0avgtext+0avgdata<span class="w"> </span>468maxresident<span class="o">)</span>k<span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span>0inputs+0outputs<span class="w"> </span><span class="o">(</span>0major+21minor<span class="o">)</span>pagefaults<span class="w"> </span>0swaps
|
||||
</span></pre>
|
||||
<p>(Read: <cite>c-lolcat << python-lolcat << ruby-lolcat</cite>)</p>
|
||||
</div>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
projects/lolcat-c/screenshot.png
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
projects/lolcat-c/sl.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
408
projects/python-mpv/index.html
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>python-mpv | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>python-mpv</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/python-mpv/">python-mpv</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/python-mpv.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/python-mpv/issues">Issues</a>
|
||||
<a href="https://neinseg.gitlab.io/python-mpv">Docs</a>
|
||||
<a href="https://pypi.org/project/mpv">PyPI</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<!-- vim: tw=120 sw=4 et -->
|
||||
<p>python-mpv is a ctypes-based python interface to the mpv media player. It gives you more or less full control of all
|
||||
features of the player, just as the lua interface does.</p>
|
||||
<div class="section" id="installation">
|
||||
<h2>Installation</h2>
|
||||
<pre class="code bash literal-block">
|
||||
<span class="lineno"></span><span class="line">pip<span class="w"> </span>install<span class="w"> </span>mpv
|
||||
</span></pre>
|
||||
<p>...though you can also realistically just copy <a class="reference external" href="https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py">mpv.py</a> into your project as it's all nicely contained in one file.</p>
|
||||
<div class="section" id="requirements">
|
||||
<h3>Requirements</h3>
|
||||
<div class="section" id="libmpv">
|
||||
<h4>libmpv</h4>
|
||||
<p><tt class="docutils literal">libmpv.so</tt> either locally (in your current working directory) or somewhere in your system library search path. This
|
||||
module is somewhat lenient as far as <tt class="docutils literal">libmpv</tt> versions are concerned but since <tt class="docutils literal">libmpv</tt> is changing quite frequently
|
||||
you'll only get all the newest features when using an up-to-date version of this module. The unit tests for this module
|
||||
do some basic automatic version compatibility checks. If you discover anything missing here, please open an <a class="reference external" href="https://github.com/jaseg/python-mpv/issues">issue</a> or
|
||||
submit a <a class="reference external" href="https://github.com/jaseg/python-mpv/pulls">pull request</a> on github.</p>
|
||||
<p>On Windows you can place libmpv anywhere in your <tt class="docutils literal">%PATH%</tt> (e.g. next to <tt class="docutils literal">python.exe</tt>) or next to this module's
|
||||
<tt class="docutils literal">mpv.py</tt>. Before falling back to looking in the mpv module's directory, python-mpv uses the DLL search order built
|
||||
into ctypes, which is different to the one Windows uses internally. Consult <a class="reference external" href="https://stackoverflow.com/a/23805306">this stackoverflow post</a> for details.</p>
|
||||
</div>
|
||||
<div class="section" id="python-3-7-officially">
|
||||
<h4>Python >= 3.7 (officially)</h4>
|
||||
<p>The <tt class="docutils literal">main</tt> branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated
|
||||
but functional <a class="reference external" href="https://github.com/jaseg/python-mpv/tree/py2compat">py2compat branch</a> providing Python 2 compatibility.</p>
|
||||
</div>
|
||||
<div class="section" id="supported-platforms">
|
||||
<h4>Supported Platforms</h4>
|
||||
<p><strong>Linux</strong>, <strong>Windows</strong> and <strong>OSX</strong> all seem to work mostly fine. For some notes on the installation on Windows see
|
||||
<a class="reference external" href="https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773">this comment</a>. Shared library handling is quite bad on windows, so expect some pain there. On OSX there seems to be
|
||||
some bug int the event logic. See <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/36">issue 36</a> and <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">issue 61</a> for details. Creating a pyQT window and having mpv draw
|
||||
into it seems to be a workaround (about 10loc), but in case you want this fixed please weigh in on the issue tracker
|
||||
since right now there is not many OSX users.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h2>Usage</h2>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">ytdl</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'https://youtu.be/DOmdB7D-pUU'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
<p>python-mpv mostly exposes mpv's built-in API to python, adding only some porcelain on top. Most "<a class="reference external" href="https://mpv.io/manual/master/#list-of-input-commands">input commands</a>" are mapped to methods of the MPV class. Check out these methods and their docstrings in <a class="reference external" href="https://github.com/jaseg/python-mpv/blob/main/mpv.py">the source</a> for things you can do. Additional controls and status information are exposed through <a class="reference external" href="https://mpv.io/manual/master/#properties">MPV properties</a>. These can be accessed like <tt class="docutils literal">player.metadata</tt>, <tt class="docutils literal">player.fullscreen</tt> and <tt class="docutils literal">player.loop_playlist</tt>.</p>
|
||||
<div class="section" id="threading">
|
||||
<h3>Threading</h3>
|
||||
<p>The <tt class="docutils literal">mpv</tt> module starts one thread for event handling, since MPV sends events that must be processed quickly. The
|
||||
event queue has a fixed maxmimum size and some operations can cause a large number of events to be sent.</p>
|
||||
<p>If you want to handle threading yourself, you can pass <tt class="docutils literal">start_event_thread=False</tt> to the <tt class="docutils literal">MPV</tt> constructor and
|
||||
manually call the <tt class="docutils literal">MPV</tt> object's <tt class="docutils literal">_loop</tt> function. If you have some strong need to not use threads and use some
|
||||
external event loop (such as asyncio) instead you can do that, too with some work. The API of the backend C <tt class="docutils literal">libmpv</tt>
|
||||
has a function for producing a sort of event file descriptor for a handle. You can use that to produce a file descriptor
|
||||
that can be passed to an event loop to tell it to wake up the python-mpv event handler on every incoming event.</p>
|
||||
<p>All API functions are thread-safe. If one is not, please file an issue on github.</p>
|
||||
</div>
|
||||
<div class="section" id="advanced-usage">
|
||||
<h3>Advanced Usage</h3>
|
||||
<div class="section" id="logging-properties-python-key-bindings-screenshots-and-youtube-dl">
|
||||
<h4>Logging, Properties, Python Key Bindings, Screenshots and youtube-dl</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">my_log</span><span class="p">(</span><span class="n">loglevel</span><span class="p">,</span> <span class="n">component</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">print</span><span class="p">(</span><span class="s1">'[</span><span class="si">{}</span><span class="s1">] </span><span class="si">{}</span><span class="s1">: </span><span class="si">{}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">loglevel</span><span class="p">,</span> <span class="n">component</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">log_handler</span><span class="o">=</span><span class="n">my_log</span><span class="p">,</span> <span class="n">ytdl</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">input_default_bindings</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">input_vo_keyboard</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="c1"># Property access, these can be changed at runtime</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nd">@player</span><span class="o">.</span><span class="n">property_observer</span><span class="p">(</span><span class="s1">'time-pos'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">time_observer</span><span class="p">(</span><span class="n">_name</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># Here, _value is either None if nothing is playing or a float containing</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># fractional seconds since the beginning of the file.</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">print</span><span class="p">(</span><span class="s1">'Now playing at </span><span class="si">{:.2f}</span><span class="s1">s'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">value</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">fullscreen</span> <span class="o">=</span> <span class="kc">True</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">loop_playlist</span> <span class="o">=</span> <span class="s1">'inf'</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="c1"># Option access, in general these require the core to reinitialize</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="p">[</span><span class="s1">'vo'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'gpu'</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nd">@player</span><span class="o">.</span><span class="n">on_key_press</span><span class="p">(</span><span class="s1">'q'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">my_q_binding</span><span class="p">():</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">print</span><span class="p">(</span><span class="s1">'THERE IS NO ESCAPE'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nd">@player</span><span class="o">.</span><span class="n">on_key_press</span><span class="p">(</span><span class="s1">'s'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">my_s_binding</span><span class="p">():</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">pillow_img</span> <span class="o">=</span> <span class="n">player</span><span class="o">.</span><span class="n">screenshot_raw</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">pillow_img</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s1">'screenshot.png'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'https://youtu.be/DLzxrzFCyOs'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">del</span> <span class="n">player</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="skipping-silence-using-libav-filters">
|
||||
<h4>Skipping silence using libav filters</h4>
|
||||
<p>The following code uses the libav silencedetect filter to skip silence at the beginning of a file. It works by loading
|
||||
the filter, then parsing its output from mpv's log. Thanks to Sean DeNigris on github (#202) for the original code!</p>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">sys</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">p</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">p</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">skip_silence</span><span class="p">():</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">set_loglevel</span><span class="p">(</span><span class="s1">'debug'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">af</span> <span class="o">=</span> <span class="s1">'lavfi=[silencedetect=n=-20dB:d=1]'</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">speed</span> <span class="o">=</span> <span class="mi">100</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="n">evt</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">toks</span> <span class="o">=</span> <span class="n">evt</span><span class="p">[</span><span class="s1">'event'</span><span class="p">][</span><span class="s1">'text'</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">if</span> <span class="s1">'silence_end:'</span> <span class="ow">in</span> <span class="n">toks</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">toks</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">time_pos</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">wait_for_event</span><span class="p">(</span><span class="s1">'log_message'</span><span class="p">,</span> <span class="n">cond</span><span class="o">=</span><span class="n">check</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">speed</span> <span class="o">=</span> <span class="mi">1</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">p</span><span class="o">.</span><span class="n">af</span> <span class="o">=</span> <span class="s1">''</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">skip_silence</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">p</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="video-overlays">
|
||||
<h4>Video overlays</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">time</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span><span class="p">,</span> <span class="n">ImageDraw</span><span class="p">,</span> <span class="n">ImageFont</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">loop</span> <span class="o">=</span> <span class="kc">True</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'test.webm'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_until_playing</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">font</span> <span class="o">=</span> <span class="n">ImageFont</span><span class="o">.</span><span class="n">truetype</span><span class="p">(</span><span class="s1">'DejaVuSans.ttf'</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">while</span> <span class="ow">not</span> <span class="n">player</span><span class="o">.</span><span class="n">core_idle</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">overlay</span> <span class="o">=</span> <span class="n">player</span><span class="o">.</span><span class="n">create_image_overlay</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">for</span> <span class="n">pos</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">500</span><span class="p">,</span> <span class="mi">5</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">ts</span> <span class="o">=</span> <span class="n">player</span><span class="o">.</span><span class="n">time_pos</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">if</span> <span class="n">ts</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">break</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s1">'RGBA'</span><span class="p">,</span> <span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">150</span><span class="p">),</span> <span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">d</span> <span class="o">=</span> <span class="n">ImageDraw</span><span class="o">.</span><span class="n">Draw</span><span class="p">(</span><span class="n">img</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">d</span><span class="o">.</span><span class="n">text</span><span class="p">((</span><span class="mi">10</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span> <span class="s1">'Hello World'</span><span class="p">,</span> <span class="n">font</span><span class="o">=</span><span class="n">font</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">128</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">d</span><span class="o">.</span><span class="n">text</span><span class="p">((</span><span class="mi">10</span><span class="p">,</span> <span class="mi">60</span><span class="p">),</span> <span class="sa">f</span><span class="s1">'t=</span><span class="si">{</span><span class="n">ts</span><span class="si">:</span><span class="s1">.3f</span><span class="si">}</span><span class="s1">'</span><span class="p">,</span> <span class="n">font</span><span class="o">=</span><span class="n">font</span><span class="p">,</span> <span class="n">fill</span><span class="o">=</span><span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">overlay</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">img</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">pos</span><span class="p">,</span> <span class="n">pos</span><span class="p">))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.05</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">overlay</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="playlist-handling">
|
||||
<h4>Playlist handling</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">ytdl</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">input_default_bindings</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">input_vo_keyboard</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">playlist_append</span><span class="p">(</span><span class="s1">'https://youtu.be/PHIGke6Yzh8'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">playlist_append</span><span class="p">(</span><span class="s1">'https://youtu.be/Ji9qSuQapFY'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">playlist_append</span><span class="p">(</span><span class="s1">'https://youtu.be/6f78_Tf4Tdk'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">playlist_pos</span> <span class="o">=</span> <span class="mi">0</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">print</span><span class="p">(</span><span class="n">player</span><span class="o">.</span><span class="n">playlist</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="directly-feeding-mpv-data-from-python">
|
||||
<h4>Directly feeding mpv data from python</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="nd">@player</span><span class="o">.</span><span class="n">python_stream</span><span class="p">(</span><span class="s1">'foo'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">def</span> <span class="nf">reader</span><span class="p">():</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'test.webm'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">while</span> <span class="kc">True</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">yield</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'python://foo'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="using-external-subtitles">
|
||||
<h4>Using external subtitles</h4>
|
||||
<p>The easiest way to load custom subtitles from a file is to pass the <tt class="docutils literal"><span class="pre">--sub-file</span></tt> option to the <tt class="docutils literal">loadfile</tt> call:</p>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">loadfile</span><span class="p">(</span><span class="s1">'test.webm'</span><span class="p">,</span> <span class="n">sub_file</span><span class="o">=</span><span class="s1">'test.srt'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
<p>Note that you can also pass many other options to <tt class="docutils literal">loadfile</tt>. See the mpv docs for details.</p>
|
||||
<p>If you want to add subtitle files or streams at runtime, you can use the <tt class="docutils literal"><span class="pre">sub-add</span></tt> command. <tt class="docutils literal"><span class="pre">sub-add</span></tt> can only be
|
||||
called once the player is done loading the file and starts playing. An easy way to wait for this is to wait for the
|
||||
<tt class="docutils literal"><span class="pre">core-idle</span></tt> property.</p>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'test.webm'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_until_playing</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">sub_add</span><span class="p">(</span><span class="s1">'test.srt'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span><span class="o">.</span><span class="n">wait_for_playback</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="using-mpv-s-built-in-gui">
|
||||
<h4>Using MPV's built-in GUI</h4>
|
||||
<p>python-mpv is using mpv via libmpv. libmpv is meant for embedding into other applications and by default disables most
|
||||
GUI features such as the OSD or keyboard input. To enable the built-in GUI, use the following options when initializing
|
||||
the MPV instance. See <a class="reference external" href="https://github.com/jaseg/python-mpv/issues/61">Issue 102</a> for more details</p>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="c1"># Enable the on-screen controller and keyboard shortcuts</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">input_default_bindings</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">input_vo_keyboard</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">osc</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="c1"># Alternative version using the old "floating box" style on-screen controller</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">player_operation_mode</span><span class="o">=</span><span class="s1">'pseudo-gui'</span><span class="p">,</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">script_opts</span><span class="o">=</span><span class="s1">'osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3'</span><span class="p">,</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">input_default_bindings</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">input_vo_keyboard</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">osc</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="pyqt-embedding">
|
||||
<h4>PyQT embedding</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">sys</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">from</span> <span class="nn">PyQt5.QtWidgets</span> <span class="kn">import</span> <span class="o">*</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">from</span> <span class="nn">PyQt5.QtCore</span> <span class="kn">import</span> <span class="o">*</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">class</span> <span class="nc">Test</span><span class="p">(</span><span class="n">QMainWindow</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parent</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">container</span> <span class="o">=</span> <span class="n">QWidget</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">setCentralWidget</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">container</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">container</span><span class="o">.</span><span class="n">setAttribute</span><span class="p">(</span><span class="n">Qt</span><span class="o">.</span><span class="n">WA_DontCreateNativeAncestors</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">container</span><span class="o">.</span><span class="n">setAttribute</span><span class="p">(</span><span class="n">Qt</span><span class="o">.</span><span class="n">WA_NativeWindow</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">player</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">wid</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">container</span><span class="o">.</span><span class="n">winId</span><span class="p">())),</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">vo</span><span class="o">=</span><span class="s1">'x11'</span><span class="p">,</span> <span class="c1"># You may not need this</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">log_handler</span><span class="o">=</span><span class="nb">print</span><span class="p">,</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">loglevel</span><span class="o">=</span><span class="s1">'debug'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">player</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s1">'test.webm'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">app</span> <span class="o">=</span> <span class="n">QApplication</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="c1"># This is necessary since PyQT stomps over the locale settings needed by libmpv.</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="c1"># This needs to happen after importing PyQT before creating the first mpv.MPV instance.</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">locale</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">locale</span><span class="o">.</span><span class="n">setlocale</span><span class="p">(</span><span class="n">locale</span><span class="o">.</span><span class="n">LC_NUMERIC</span><span class="p">,</span> <span class="s1">'C'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">win</span> <span class="o">=</span> <span class="n">Test</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">win</span><span class="o">.</span><span class="n">show</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">exec_</span><span class="p">())</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="pygobject-embedding">
|
||||
<h4>PyGObject embedding</h4>
|
||||
<pre class="code python literal-block">
|
||||
<span class="lineno"></span><span class="line"><span class="ch">#!/usr/bin/env python3</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">gi</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">import</span> <span class="nn">mpv</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="n">gi</span><span class="o">.</span><span class="n">require_version</span><span class="p">(</span><span class="s1">'Gtk'</span><span class="p">,</span> <span class="s1">'3.0'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="kn">from</span> <span class="nn">gi.repository</span> <span class="kn">import</span> <span class="n">Gtk</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">class</span> <span class="nc">MainClass</span><span class="p">(</span><span class="n">Gtk</span><span class="o">.</span><span class="n">Window</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="nb">super</span><span class="p">(</span><span class="n">MainClass</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">set_default_size</span><span class="p">(</span><span class="mi">600</span><span class="p">,</span> <span class="mi">400</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">"destroy"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">on_destroy</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">widget</span> <span class="o">=</span> <span class="n">Gtk</span><span class="o">.</span><span class="n">Frame</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">widget</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">show_all</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># Must be created >after< the widget is shown, else property 'window' will be None</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">mpv</span> <span class="o">=</span> <span class="n">mpv</span><span class="o">.</span><span class="n">MPV</span><span class="p">(</span><span class="n">wid</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">widget</span><span class="o">.</span><span class="n">get_property</span><span class="p">(</span><span class="s2">"window"</span><span class="p">)</span><span class="o">.</span><span class="n">get_xid</span><span class="p">()))</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">mpv</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="s2">"test.webm"</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="k">def</span> <span class="nf">on_destroy</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">widget</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="bp">self</span><span class="o">.</span><span class="n">mpv</span><span class="o">.</span><span class="n">terminate</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">Gtk</span><span class="o">.</span><span class="n">main_quit</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv.</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="c1"># Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance.</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="kn">import</span> <span class="nn">locale</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">locale</span><span class="o">.</span><span class="n">setlocale</span><span class="p">(</span><span class="n">locale</span><span class="o">.</span><span class="n">LC_NUMERIC</span><span class="p">,</span> <span class="s1">'C'</span><span class="p">)</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">application</span> <span class="o">=</span> <span class="n">MainClass</span><span class="p">()</span><span class="w"></span></span>
|
||||
<span class="lineno"></span><span class="line"><span class="w"></span> <span class="n">Gtk</span><span class="o">.</span><span class="n">main</span><span class="p">()</span>
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="using-opengl-from-pygobject">
|
||||
<h4>Using OpenGL from PyGObject</h4>
|
||||
<p>Just like it is possible to render into a GTK widget through X11 windows, it <a class="reference external" href="https://gist.github.com/jaseg/657e8ecca3267c0d82ec85d40f423caa">also is possible to render into a GTK
|
||||
widget using OpenGL</a> through this python API.</p>
|
||||
</div>
|
||||
<div class="section" id="using-opengl-from-pyqt5-qml">
|
||||
<h4>Using OpenGL from PyQt5/QML</h4>
|
||||
<p><a class="reference external" href="https://gitlab.com/robozman">Robozman</a> has mangaed to <a class="reference external" href="https://gitlab.com/robozman/python-mpv-qml-example">make mpv render into a PyQt5/QML widget using OpenGL</a> through this python API.</p>
|
||||
</div>
|
||||
<div class="section" id="using-mpv-inside-imgui-inside-opengl-via-glfw">
|
||||
<h4>Using mpv inside imgui inside OpenGL via GLFW</h4>
|
||||
<p><a class="reference external" href="https://github.com/dfaker">dfaker</a> has written a demo (<a class="reference external" href="https://github.com/dfaker/imgui_glfw_pythonmpv_demo/blob/main/main.py">link</a>) that uses mpv to render video into an <a class="reference external" href="https://github.com/ocornut/imgui">imgui</a> UI running on an OpenGL context inside <a class="reference external" href="https://www.glfw.org/">GLFW</a>. Check out their demo to see how to integrate with imgui/OpenGL and how to access properties and manage the lifecycle of an MPV instance.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="running-tests">
|
||||
<h2>Running tests</h2>
|
||||
<p>Use pytest to run tests.</p>
|
||||
</div>
|
||||
<div class="section" id="coding-conventions">
|
||||
<h2>Coding Conventions</h2>
|
||||
<p>The general aim is <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/">PEP 8</a>, with liberal application of the "consistency" section. 120 cells line width. Four spaces.
|
||||
No tabs. Probably don't bother making pure-formatting PRs except if you think it <em>really</em> helps readability or it
|
||||
<em>really</em> irks you if you don't.</p>
|
||||
</div>
|
||||
<div class="section" id="license">
|
||||
<h2>License</h2>
|
||||
<p>python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later.
|
||||
For details, see <a class="reference external" href="https://github.com/mpv-player/mpv/blob/master/Copyright">the mpv copyright page</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
63
projects/svg-flatten/index.html
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>svg-flatten | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>svg-flatten</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/svg-flatten/">svg-flatten</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/gerbolyze.git/tree/svg-flatten?h=main">Sources</a>
|
||||
<a href="https://github.com/jaseg/gerbolyze/issues">Issues</a>
|
||||
<a href="https://gerbolyze.gitlab.io/svg-flatten">Docs</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>svg-flatten is a command-line utility that performs vector occlusion and clipping on SVG files, producing a flattened
|
||||
SVG file without overlapping elements, without changing what the file looks like. svg-flatten is used as a part of
|
||||
gerbolyze.</p>
|
||||
<p>I developed svg-flatten as part of <a class="reference external" href="http://jaseg.de/projects/gerbolyze/">gerbolyze</a>, but it can be used independently.</p>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
105
projects/wsdiff/index.html
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<!DOCTYPE html>
|
||||
<html><head>
|
||||
<meta charset="utf-8">
|
||||
<title>wsdiff | Home</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="color-scheme" content="dark light">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body><nav>
|
||||
<div class="internal">
|
||||
|
||||
<a href="/" title="Home">Home</a>
|
||||
<a href="/blog/" title="Blog">Blog</a>
|
||||
<a href="/projects/" title="Projects">Projects</a>
|
||||
<a href="/about/" title="About">About</a>
|
||||
</div>
|
||||
<div class="external">
|
||||
<a href="https://git.jaseg.de/" title="cgit">cgit</a>
|
||||
<a href="https://github.com/jaseg" title="Github">Github</a>
|
||||
<a href="https://gitlab.com/neinseg" title="Gitlab">Gitlab</a>
|
||||
<a href="https://chaos.social/jaseg" title="Mastodon">Mastodon</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<h1>wsdiff</h1>
|
||||
<ul class="breadcrumbs">
|
||||
<li><a href="/">jaseg.de</a></li>
|
||||
<li><a href="/projects/">Projects</a></li><li><a href="/projects/wsdiff/">wsdiff</a></li>
|
||||
</ul>
|
||||
|
||||
</header>
|
||||
<main>
|
||||
<div class="links">
|
||||
<a href="https://git.jaseg.de/wsdiff.git">Sources</a>
|
||||
<a href="https://github.com/jaseg/wsdiff/issues">Issues</a>
|
||||
<a href="https://pypi.org/project/wsdiff">PyPI</a>
|
||||
</div>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<p>wsdiff is a python script that produces a diff of two files or directories as a single, self-contained HTML file. The
|
||||
resulting diff works without Javascript and will automatically switch between inline and side-by-side formats depending
|
||||
on available screen space.</p>
|
||||
<div class="section" id="installation">
|
||||
<h2>Installation</h2>
|
||||
<pre class="code sh literal-block">
|
||||
<span class="lineno"></span><span class="line">$<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>wsdiff
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h2>Usage</h2>
|
||||
<pre class="literal-block">
|
||||
<span class="lineno"></span><span class="line">usage: wsdiff [-h] [-b] [-s SYNTAX_CSS] [-l LEXER] [-L] [-t PAGETITLE]</span>
|
||||
<span class="lineno"></span><span class="line"> [-o OUTPUT] [--header] [--content]</span>
|
||||
<span class="lineno"></span><span class="line"> [old] [new]</span>
|
||||
<span class="lineno"></span><span class="line"></span>
|
||||
<span class="lineno"></span><span class="line">Given two source files or directories this application creates an html page</span>
|
||||
<span class="lineno"></span><span class="line">that highlights the differences between the two.</span>
|
||||
<span class="lineno"></span><span class="line"></span>
|
||||
<span class="lineno"></span><span class="line">positional arguments:</span>
|
||||
<span class="lineno"></span><span class="line"> old source file or directory to compare ("before" file)</span>
|
||||
<span class="lineno"></span><span class="line"> new source file or directory to compare ("after" file)</span>
|
||||
<span class="lineno"></span><span class="line"></span>
|
||||
<span class="lineno"></span><span class="line">options:</span>
|
||||
<span class="lineno"></span><span class="line"> -h, --help show this help message and exit</span>
|
||||
<span class="lineno"></span><span class="line"> -b, --open Open output file in a browser</span>
|
||||
<span class="lineno"></span><span class="line"> -s SYNTAX_CSS, --syntax-css SYNTAX_CSS</span>
|
||||
<span class="lineno"></span><span class="line"> Path to custom Pygments CSS file for code syntax</span>
|
||||
<span class="lineno"></span><span class="line"> highlighting</span>
|
||||
<span class="lineno"></span><span class="line"> -l LEXER, --lexer LEXER</span>
|
||||
<span class="lineno"></span><span class="line"> Manually select pygments lexer (default: guess from</span>
|
||||
<span class="lineno"></span><span class="line"> filename, use -L to list available lexers.)</span>
|
||||
<span class="lineno"></span><span class="line"> -L, --list-lexers List available lexers for -l/--lexer</span>
|
||||
<span class="lineno"></span><span class="line"> -t PAGETITLE, --pagetitle PAGETITLE</span>
|
||||
<span class="lineno"></span><span class="line"> Override page title of output HTML file</span>
|
||||
<span class="lineno"></span><span class="line"> -o OUTPUT, --output OUTPUT</span>
|
||||
<span class="lineno"></span><span class="line"> Name of output file (default: stdout)</span>
|
||||
<span class="lineno"></span><span class="line"> --header Only output HTML header with stylesheets and stuff,</span>
|
||||
<span class="lineno"></span><span class="line"> and no diff</span>
|
||||
<span class="lineno"></span><span class="line"> --content Only output HTML content, without header
|
||||
</span></pre>
|
||||
</div>
|
||||
<div class="section" id="example-output">
|
||||
<h2>Example Output</h2>
|
||||
<img alt="latest.png" src="latest.png" />
|
||||
</div>
|
||||
</div>
|
||||
</main><footer>
|
||||
Copyright © 2023 Jan Sebastian Götte
|
||||
/ <a href="/about/">About</a>
|
||||
/ <a href="/imprint/">Imprint</a>
|
||||
</footer>
|
||||
<script>
|
||||
if(navigator.getEnvironmentIntegrity!==undefined)document.querySelector('body').innerHTML=`<h1>Your browser
|
||||
contains Google DRM</h1>"Web Environment Integrity" is a Google euphemism for a DRM that is designed to
|
||||
prevent ad-blocking, and which Google has forced into their browsers against widespread public opposition.
|
||||
In support of an open web, this website does not function with this DRM. Please install a browser such
|
||||
as <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a> that respects your freedom and supports
|
||||
ad blockers.`;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
projects/wsdiff/latest.png
Normal file
|
After Width: | Height: | Size: 134 KiB |