From 92e3b5f49f6f5336530988e7839ab3ed283b86e4 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 19 Mar 2023 00:53:31 +0100 Subject: Big site update --- content/projects/_index.rst | 6 + content/projects/gerbolyze/README.rst | 700 ++ content/projects/gerbolyze/index.rst | 17 + content/projects/gerbolyze/pics/ex-flattening.png | Bin 0 -> 47137 bytes .../projects/gerbolyze/pics/ex-intersections.png | Bin 0 -> 48558 bytes content/projects/gerbolyze/pics/ex-strokes.png | Bin 0 -> 67441 bytes content/projects/gerbolyze/pics/ex-svg-joins.png | Bin 0 -> 18659 bytes content/projects/gerbolyze/pics/ex-svg-strokes.png | Bin 0 -> 67441 bytes content/projects/gerbolyze/pics/ex-svg-winding.png | Bin 0 -> 34356 bytes .../projects/gerbolyze/pics/fr4_comparison2.jpg | Bin 0 -> 271943 bytes .../gerbolyze/pics/pcbway_sample_01_small.jpg | Bin 0 -> 453117 bytes .../gerbolyze/pics/pcbway_sample_02_small.jpg | Bin 0 -> 521032 bytes .../gerbolyze/pics/pcbway_sample_03_small.jpg | Bin 0 -> 746718 bytes .../projects/gerbolyze/pics/process-overview.png | Bin 0 -> 516640 bytes .../projects/gerbolyze/pics/process-overview.svg | 7230 ++++++++++++++++++++ content/projects/gerbolyze/pics/sample1.jpg | Bin 0 -> 299841 bytes content/projects/gerbolyze/pics/sample2.jpg | Bin 0 -> 251440 bytes content/projects/gerbolyze/pics/sample3.jpg | Bin 0 -> 171160 bytes .../projects/gerbolyze/pics/subtract_example.png | Bin 0 -> 237770 bytes .../projects/gerbolyze/pics/test_svg_readme.svg | 515 ++ .../gerbolyze/pics/test_svg_readme_composited.png | Bin 0 -> 1211058 bytes .../gerbolyze/pics/vec_contours_composited.png | Bin 0 -> 40471 bytes .../gerbolyze/pics/vec_hexgrid_composited.png | Bin 0 -> 249235 bytes .../gerbolyze/pics/vec_poisson_composited.png | Bin 0 -> 278253 bytes .../gerbolyze/pics/vec_square_composited.png | Bin 0 -> 201613 bytes content/projects/gerbonara/index.rst | 141 + content/projects/lolcat-c/LOLCat-Rainbow.jpg | Bin 0 -> 42785 bytes content/projects/lolcat-c/index.rst | 105 + content/projects/lolcat-c/screenshot.png | Bin 0 -> 198032 bytes content/projects/lolcat-c/sl.gif | Bin 0 -> 1466027 bytes content/projects/python-mpv/README.rst | 401 ++ content/projects/python-mpv/index.rst | 18 + content/projects/svg-flatten/index.rst | 15 + content/projects/wsdiff/index.rst | 63 + content/projects/wsdiff/latest.png | Bin 0 -> 136920 bytes 35 files changed, 9211 insertions(+) create mode 100644 content/projects/_index.rst create mode 100644 content/projects/gerbolyze/README.rst create mode 100644 content/projects/gerbolyze/index.rst create mode 100644 content/projects/gerbolyze/pics/ex-flattening.png create mode 100644 content/projects/gerbolyze/pics/ex-intersections.png create mode 100644 content/projects/gerbolyze/pics/ex-strokes.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-joins.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-strokes.png create mode 100644 content/projects/gerbolyze/pics/ex-svg-winding.png create mode 100644 content/projects/gerbolyze/pics/fr4_comparison2.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg create mode 100644 content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg create mode 100644 content/projects/gerbolyze/pics/process-overview.png create mode 100644 content/projects/gerbolyze/pics/process-overview.svg create mode 100644 content/projects/gerbolyze/pics/sample1.jpg create mode 100644 content/projects/gerbolyze/pics/sample2.jpg create mode 100644 content/projects/gerbolyze/pics/sample3.jpg create mode 100644 content/projects/gerbolyze/pics/subtract_example.png create mode 100644 content/projects/gerbolyze/pics/test_svg_readme.svg create mode 100644 content/projects/gerbolyze/pics/test_svg_readme_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_contours_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_hexgrid_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_poisson_composited.png create mode 100644 content/projects/gerbolyze/pics/vec_square_composited.png create mode 100644 content/projects/gerbonara/index.rst create mode 100644 content/projects/lolcat-c/LOLCat-Rainbow.jpg create mode 100644 content/projects/lolcat-c/index.rst create mode 100644 content/projects/lolcat-c/screenshot.png create mode 100644 content/projects/lolcat-c/sl.gif create mode 100644 content/projects/python-mpv/README.rst create mode 100644 content/projects/python-mpv/index.rst create mode 100644 content/projects/svg-flatten/index.rst create mode 100644 content/projects/wsdiff/index.rst create mode 100644 content/projects/wsdiff/latest.png (limited to 'content/projects') diff --git a/content/projects/_index.rst b/content/projects/_index.rst new file mode 100644 index 0000000..c975627 --- /dev/null +++ b/content/projects/_index.rst @@ -0,0 +1,6 @@ +--- +title: Projects +--- +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. diff --git a/content/projects/gerbolyze/README.rst b/content/projects/gerbolyze/README.rst new file mode 100644 index 0000000..cfa7673 --- /dev/null +++ b/content/projects/gerbolyze/README.rst @@ -0,0 +1,700 @@ +Gerbolyze renders SVG vector and PNG/JPG raster images into existing gerber PCB manufacturing files. +Vector data from SVG files is rendered losslessly *without* an intermediate rasterization/revectorization step. +Still, gerbolyze supports (almost) the full SVG 1.1 spec including complex, self-intersecting paths with holes, +patterns, dashes and transformations. + +Raster images can either be vectorized through contour tracing (like gerbolyze v1.0 did) or they can be embedded using +high-resolution grayscale emulation while (mostly) guaranteeing trace/space design rules. + +Try gerbolyze online at https://dyna.kokoroyukuma.de/gerboweb + +.. figure:: pics/pcbway_sample_02_small.jpg + :width: 800px + + Drawing by `トーコ Toko `__ converted using Gerbolyze and printed at PCBWay. + + +Tooling for PCB art is quite limited in both open source and closed source ecosystems. Something as simple as putting a +pretty picture on a PCB can be an extremely tedious task. Depending on the PCB tool used, various arcane incantations +may be necessary and even modestly complex images will slow down most PCB tools to a crawl. + +Gerbolyze solves this problem in a toolchain-agnostic way by directly vectorizing 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. + +Gerbolyze is based on gerbonara_. + +.. image:: pics/process-overview.png + :width: 800px + +.. contents:: + +Tl;dr: Produce high-quality artistic PCBs in three easy steps! +-------------------------------------------------------------- + +Gerbolyze works in three steps. + +1. Generate a scale-accurate template of the finished PCB from your CAD tool's gerber output: + + .. code:: + + $ gerbolyze template --top template_top.svg [--bottom template_bottom.svg] my_gerber_dir + +2. Load the resulting template image Inkscape_ or another SVG editing program. Put your artwork on the appropriate SVG + layer. Dark colors become filled gerber primitives, bright colors become unfilled primitives. You can directly put + raster images (PNG/JPG) into this SVG as well, just position and scale them like everything else. SVG clips work for + images, too. Masks are not supported. + +3. Vectorize the edited SVG template image drectly into the PCB's gerber files: + + .. code:: + + $ gerbolyze paste --top template_top_edited.svg [--bottom ...] my_gerber_dir output_gerber_dir + +Quick Start Installation (Any Platform) +--------------------------------------- + +.. code-block:: shell + + python -m pip install --user gerbolyze + +To uninstall, run + +.. code-block:: shell + + python -m pip uninstall gerbolyze gerbonara resvg-wasi svg-flatten-wasi + +To update, run + +.. code-block:: shell + + python -m pip install --user --upgrade --upgrade-strategy eager gerbolyze + +Speeding up gerbolyze using natively-built binaries +--------------------------------------------------- + +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. + +WASM is slower than natively-built binaries. To speed up gerbolyze, you can natively build its two binary dependencies: + +1. Install resvg natively using rust's cargo package manager: ``cargo install resvg`` +2. Install gerbolyze's svg-flatten utility natively. You can get pre-built binaries from gerbolyze's gitlab CI jobs `at + this link `__ 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 ``make`` inside the ``svg-flatten`` folder from + a gerbolyze checkout. + +Gerbolyze will pick up these binaries when installed in your ``$PATH``. resvg is also picked up when it is installed by +cargo in your home's ``~/.cargo``, even if it's not in your ``$PATH``. You can override the resvg, usvg or svg-flatten +binary that gerbolyze uses by giving it the absoulute path to a binary in the ``$RESVG``, ``$USVG`` and ``$SVG_FLATTEN`` +environment variables. + + +Build from source (any distro) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: shell + + git clone --recurse-submodules https://git.jaseg.de/gerbolyze.git + cd gerbolyze + + python3 -m venv + source venv/bin/activate + python3 setup.py install + +Features +-------- + +Input on the left, output on the right. + +.. image:: pics/test_svg_readme_composited.png + :width: 800px + +* Almost full SVG 1.1 static spec coverage (!) + + * Paths with beziers, self-intersections and holes + * Strokes, even with dashes and markers + * Pattern fills and strokes + * Transformations and nested groups + * Proper text rendering with support for complex text layout (e.g. Arabic) + * elements via either built-in vectorizer or built-in halftone processor + * (some) CSS + +* Writes Gerber, SVG or KiCAD S-Expression (``.kicad_mod``) formats +* Can export from top/bottom SVGs to a whole gerber layer stack at once with filename autodetection +* Can export SVGs to ``.kicad_mod`` files like svg2mod (but with full SVG support) +* Beziers flattening with configurable tolerance using actual math! +* Polygon intersection removal +* Polygon hole removal (!) +* Optionally vector-compositing of output: convert black/white/transparent image to black/transparent image +* Renders SVG templates from input gerbers for accurate and easy scaling and positioning of artwork +* layer masking with offset (e.g. all silk within 1mm of soldermask) +* Can read gerbers from zip files +* Limited SVG support for board outline layers (no fill/region support) +* Dashed lines supported on board outline layers + +Gerbolyze is the end-to-end "paste this svg into these gerbers" command that handles all layers on both board sides at +once. The heavy-duty computer geometry logic of gerbolyze is handled by the svg-flatten utility (``svg-flatten`` +directory). svg-flatten reads an SVG file and renders it into a variety of output formats. svg-flatten can be used like +a variant of the popular svg2mod that supports all of SVG and handles arbitrary input ```` elements. + +Algorithm Overview +------------------ + +This is the algorithm gerbolyze uses to process a stack of gerbers. + +* Map input files to semantic layers by their filenames +* For each layer: + + * load input gerber + * Pass mask layers through ``gerbv`` for conversion to SVG + * Pass mask layers SVG through ``svg-flatten --dilate`` + * Pass input SVG through ``svg-flatten --only-groups [layer]`` + * Overlay input gerber, mask and input svg + * Write result to output gerber + +This is the algorithm svg-flatten uses to process an SVG. + +* pass input SVG through usvg_ +* iterate depth-first through resulting SVG. + + * for groups: apply transforms and clip and recurse + * for images: Vectorize using selected vectorizer + * for paths: + + * flatten path using Cairo + * remove self-intersections using Clipper + * if stroke is set: process dash, then offset using Clipper + * apply pattern fills + * clip to clip-path + * remove holes using Clipper + +* for KiCAD S-Expression export: vector-composite results using CavalierContours: subtract each clear output primitive + from all previous dark output primitives + +Web interface +------------- + +You can try gerbolyze online at https://dyna.kokoroyukuma.de/gerboweb + +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 Inkscape_. Finally, upload the +modified template and let gerbolyze process your design. + +Command-line usage +------------------ +.. _command_line_usage: + +Generate SVG template from Gerber files: + +.. code-block:: shell + + gerbolyze template [options] [--top|--bottom] input_dir_or.zip output.svg + +Render design from an SVG made with the template above into a set of gerber files: + +.. code-block:: shell + + gerbolyze paste [options] artwork.svg input_dir_or.zip output_dir_or.zip + +Use svg-flatten to convert an SVG file into Gerber or flattened SVG: + +.. code-block:: shell + + svg-flatten [options] --format [gerber|svg] [input_file.svg] [output_file] + +Use svg-flatten to convert an SVG file into the given layer of a KiCAD S-Expression (``.kicad_mod``) file: + +.. code-block:: shell + + svg-flatten [options] --format kicad --sexp-layer F.SilkS --sexp-mod-name My_Module [input_file.svg] [output_file] + +Use svg-flatten to convert an SVG file into a ``.kicad_mod`` with SVG layers fed into separate KiCAD layers based on +their IDs like the popular ``svg2mod`` is doing: + +Note: + Right now, the input SVG's layers must have *ids* that match up KiCAD's s-exp layer names. Note that when you name + a layer in Inkscape that only sets a ``name`` 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. + + Also note that svg-flatten expects the layer names KiCAD uses in their S-Expression format. These are *different* to + the layer names KiCAD exposes in the UI (even though most of them match up!). + + For your convenience, there is an SVG template with all the right layer names and IDs located next to this README. + +.. code-block:: shell + + svg-flatten [options] --format kicad --sexp-mod-name My_Module [input_file.svg] [output_file] + +``gerbolyze template`` +~~~~~~~~~~~~~~~~~~~~~~ + +Usage: ``gerbolyze template [OPTIONS] INPUT`` + +Generate SVG template for gerbolyze paste from gerber files. + +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. + +Options: +******** +``--top | --bottom`` + Output top or bottom side template. This affects both the preview image and the prepared Inkscape layers. + +``--vector | --raster`` + 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. + +``--raster-dpi FLOAT`` + DPI for rastering preview + +``--bbox TEXT`` + 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. + + +``gerbolyze paste`` +~~~~~~~~~~~~~~~~~~~ +(see `below `__) + +Usage: ``gerbolyze paste [OPTIONS] INPUT_GERBERS OVERLAY_SVG OUTPUT_GERBERS`` + +Render vector data and raster images from SVG file into gerbers. The SVG input file can be generated using ``gerbolyze +template`` 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. + +Options: +******** + +``--bbox TEXT`` + 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 **must match the ``--bbox`` value given to + template**! + +``--subtract TEXT`` + Use user subtraction script from argument (see `below `_) + +``--no-subtract`` + Disable subtraction (see `below `_) + +``--dilate FLOAT`` + Default dilation for subtraction operations in mm (see `below `_) + +``--trace-space FLOAT`` + Passed through to svg-flatten, see `below `__. + +``--vectorizer TEXT`` + Passed through to svg-flatten, see `its description below `__. Also have a look at `the examples below `_. + +``--vectorizer-map TEXT`` + Passed through to svg-flatten, see `below `__. + +``--exclude-groups TEXT`` + Passed through to svg-flatten, see `below `__. + + +.. _outline_layers: + +Outline layers +************** + +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. + +One exception from this are patterns, which work as expected for both fills and strokes with full support for joins and +end caps. + +Dashed strokes are supported on outline layers and can be used to make easy mouse bites. + +.. _subtraction_script: + +Subtraction scripts +******************* + +.. image:: pics/subtract_example.png + :width: 800px + +Subtraction scripts tell ``gerbolyze paste`` 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 ``--no-subtract`` or pass your own "script". + +The syntax of these scripts is: + +.. code-block:: + + {target layer} -= {source layer} {dilation} [; ...] + +The target layer must be ``out.{layer name}`` and the source layer ``in.{layer name}``. The layer names are gerbolyze's +internal layer names, i.e.: ``paste, silk, mask, copper, outline, drill`` + +The dilation value is optional, but can be a float with a leading ``+`` or ``-``. 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 +``--dilate`` if given or 0.1 mm otherwise. To disable dilation, simply pass ``+0`` here. + +Multiple commands can be separated by semicolons ``;`` or line breaks. + +The default subtraction script is: + +.. code-block:: + + out.silk -= in.mask + out.silk -= in.silk+0.5 + out.mask -= in.mask+0.5 + out.copper -= in.copper+0.5 + +.. _svg_flatten: + +``svg-flatten`` +~~~~~~~~~~~~~~~ + +Usage: ``svg-flatten [OPTIONS]... [INPUT_FILE] [OUTPUT_FILE]`` + +Specify ``-`` for stdin/stdout. + +Options: +******** + +``-h, --help`` + Print help and exit + +``-v, --version`` + Print version and exit + +``-o, --format`` + Output format. Supported: gerber, gerber-outline (for board outline layers), svg, s-exp (KiCAD S-Expression) + +``-p, --precision`` + 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. + +``--clear-color`` + SVG color to use in SVG output for "clear" areas (default: white) + +``--dark-color`` + SVG color to use in SVG output for "dark" areas (default: black) + +``-f, --flip-gerber-polarity`` + Flip polarity of all output gerber primitives for --format gerber. + +``-d, --trace-space`` + Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm. + +``--no-header`` + Do not export output format header/footer, only export the primitives themselves + +``--flatten`` + Flatten output so it only consists of non-overlapping white polygons. This perform composition at the vector level. + Potentially slow. This defaults to on when using KiCAD S-Exp export because KiCAD does not know polarity or colors. + +``--no-flatten`` + Disable automatic flattening for KiCAD S-Exp export + +``--dilate`` + Dilate output gerber primitives by this amount in mm. Used for masking out other layers. + +``-g, --only-groups`` + Comma-separated list of group IDs to export. + +``-b, --vectorizer`` + Vectorizer to use for bitmap images. One of poisson-disc (default), hex-grid, square-grid, binary-contours, + dev-null. Have a look at `the examples below `_. + +``--vectorizer-map`` + Map from image element id to vectorizer. Overrides --vectorizer. Format: id1=vectorizer,id2=vectorizer,... + + 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 ```` element's SVG ID from within + Inkscape though the context menu's Object Properties tool. + +``--force-svg`` + Force SVG input irrespective of file name + +``--force-png`` + Force bitmap graphics input irrespective of file name + +``-s, --size`` + Bitmap mode only: Physical size of output image in mm. Format: 12.34x56.78 + +``--sexp-mod-name`` + Module name for KiCAD S-Exp output. This is a mandatory argument if using S-Exp output. + +``--sexp-layer`` + 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 ``-g`` for group selection. + +``-a, --preserve-aspect-ratio`` + Bitmap mode only: Preserve aspect ratio of image. Allowed values are meet, slice. Can also parse full SVG + preserveAspectRatio syntax. + +``--no-usvg`` + Do not preprocess input using usvg (do not use unless you know *exactly* what you're doing) + +``--usvg-dpi`` + Passed through to usvg's --dpi, in case the input file has different ideas of DPI than usvg has. + +``--scale`` + Scale input svg lengths by this factor (-o gerber only). + +``-e, --exclude-groups`` + Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups. + +.. _vectorization: + +Gerbolyze image vectorization +----------------------------- + +Gerbolyze has two built-in strategies to translate pixel images into vector images. One is its built-in halftone +processor that tries to approximate grayscale. The other is its built-in binary vectorizer that traces contours in +black-and-white images. Below are examples for the four options. + +The vectorizers can be used in isolation through ``svg-flatten`` with either an SVG input that contains an image or a +PNG/JPG input. + +The vectorizer can be controlled globally using the ``--vectorizer`` flag in both ``gerbolyze`` and ``svg-flatten``. It +can also be set on a per-image basis in both using ``--vectorizer-map [image svg id]=[option]["," ...]``. + +.. for f in vec_*.png; convert -background white -gravity center $f -resize 500x500 -extent 500x500 (basename -s .png $f)-square.png; end +.. for vec in hexgrid square poisson contours; convert vec_"$vec"_whole-square.png vec_"$vec"_detail-square.png -background transparent -splice 25x0+0+0 +append -chop 25x0+0+0 vec_"$vec"_composited.png; end + +``--vectorizer poisson-disc`` (the default) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_poisson_composited.png + :width: 800px + +``--vectorizer hex-grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_hexgrid_composited.png + :width: 800px + +``--vectorizer square-grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_square_composited.png + :width: 800px + +``--vectorizer binary-contours`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: pics/vec_contours_composited.png + :width: 800px + +The binary contours vectorizer requires a black-and-white binary input image. As you can see, like every bitmap tracer +it will produce some artifacts. For artistic input this is usually not too bad as long as the input data is +high-resolution. Antialiased edges in the input image are not only OK, they may even help with an accurate +vectorization. + +GIMP halftone preprocessing guide +--------------------------------- + +Gerbolyze has its own built-in halftone processor, but you can also use the high-quality "newsprint" filter built into +GIMP_ instead if you like. This section will guide you through this. The PNG you get out of this can then be fed into +gerbolyze using ``--vectorizer binary-contours``. + +1 Import your desired artwork +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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. + +.. image:: screenshots/02import02.png + :width: 800px + +2 Convert the image to grayscale +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. image:: screenshots/06grayscale.png + :width: 800px + +3 Fine-tune the image's contrast +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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. + +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. + +.. image:: screenshots/08curve_cut.png + :width: 800px + +4 Retouch details +~~~~~~~~~~~~~~~~~ + +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. + +If you don't want the image's background to show up on the final PCB at all, just make it black. + +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. + +.. image:: screenshots/09retouch.png + :width: 800px + +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. + +.. image:: screenshots/10retouched.png + :width: 800px + +5 Run the newsprint filter +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now, run the GIMP's newsprint filter, under filters, distorts, newsprint. + +The first important settings is the spot size, which should be larger than your PCB's minimum detail size (about 10px +with ``gerbolyze render`` 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. + +The second important setting is oversampling, which should be set to four or slightly higher. This improves the result +of the edge reconstruction of ``gerbolyze vectorize``. + +.. image:: screenshots/11newsprint.png + :width: 800px + +The following are examples on the detail resulting from the newsprint filter. + +.. image:: screenshots/12newsprint.png + :width: 800px + +6 Export the image for use with ``gerbolyze vectorize`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Simply export the image as a PNG file. Below are some pictures of the output ``gerbolyze vectorize`` produced for this +example. + +.. image:: screenshots/14result_cut.png + :width: 800px + +.. image:: screenshots/15result_cut.png + :width: 800px + +Manufacturing Considerations +---------------------------- + +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. + +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. + +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. + +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. + +PCBWay on the other hand has a much more rigurous file review process. They will 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. + +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. + +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. + +Limitations +----------- + +SVG raster features +~~~~~~~~~~~~~~~~~~~ + +Currently, SVG masks and filters are not supported. Though SVG is marketed as a "vector graphics format", these two +features are really raster primitives that all SVG viewers perform at the pixel level after rasterization. Since +supporting these would likely not end up looking like what you want, it is not a planned feature. If you need masks or +filters, simply export the relevant parts of the SVG as a PNG then include that in your template. + +Gerber pass-through +~~~~~~~~~~~~~~~~~~~ + +Since gerbolyze has to composite your input gerbers with its own output, it has to fully parse and re-serialize them. +gerbolyze gerbonara_ 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 gerbonara_ bug tracker. *Always* check the output files for errors before +submitting them to production. + +Gerbolyze is provided without any warranty, but still please open an issue or `send me an email +`__ if you find any errors or inconsistencies. + +Trace/Space design rule adherence +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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. + +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 ;) + +Gallery +------- + +.. image:: pics/sample3.jpg + :width: 400px + +For a demonstration of ``gerbolyze convert``, check out the `Gerbolyze Protoboard Index`_, where you can download gerber +files for over 7.000 SMD and THT protoboard layouts. + +Licensing +--------- + +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. + +I get that some people have issues with the AGPL. In case this license prevents you from using this software, please +send me `an email `__ 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. + +.. _usvg: https://github.com/RazrFalcon/resvg +.. _Inkscape: https://inkscape.org/ +.. _pcb-tools: https://github.com/curtacircuitos/pcb-tools +.. _pcb-tools-extension: https://github.com/opiopan/pcb-tools-extension +.. _GIMP: https://gimp.org/ +.. _gerbonara: https://gitlab.com/gerbolyze/gerbonara +.. _`Gerbolyze Protoboard Index`: https://dyna.kokoroyukuma.de/protos/ + diff --git a/content/projects/gerbolyze/index.rst b/content/projects/gerbolyze/index.rst new file mode 100644 index 0000000..47022ee --- /dev/null +++ b/content/projects/gerbolyze/index.rst @@ -0,0 +1,17 @@ +--- +title: "Gerbolyze" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbolyze.git" + - name: Issues + url: "https://github.com/jaseg/gerbolyze/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/gerbolyze" + - name: PyPI + url: "https://pypi.org/projects/gerbolyze" +summary: > + 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. +--- + +.. include:: content/projects/gerbolyze/README.rst diff --git a/content/projects/gerbolyze/pics/ex-flattening.png b/content/projects/gerbolyze/pics/ex-flattening.png new file mode 100644 index 0000000..e702733 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-flattening.png differ diff --git a/content/projects/gerbolyze/pics/ex-intersections.png b/content/projects/gerbolyze/pics/ex-intersections.png new file mode 100644 index 0000000..05ccc59 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-intersections.png differ diff --git a/content/projects/gerbolyze/pics/ex-strokes.png b/content/projects/gerbolyze/pics/ex-strokes.png new file mode 100644 index 0000000..5ef3c49 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-strokes.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-joins.png b/content/projects/gerbolyze/pics/ex-svg-joins.png new file mode 100644 index 0000000..534e4c2 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-joins.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-strokes.png b/content/projects/gerbolyze/pics/ex-svg-strokes.png new file mode 100644 index 0000000..bec71c0 Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-strokes.png differ diff --git a/content/projects/gerbolyze/pics/ex-svg-winding.png b/content/projects/gerbolyze/pics/ex-svg-winding.png new file mode 100644 index 0000000..3f85f6f Binary files /dev/null and b/content/projects/gerbolyze/pics/ex-svg-winding.png differ diff --git a/content/projects/gerbolyze/pics/fr4_comparison2.jpg b/content/projects/gerbolyze/pics/fr4_comparison2.jpg new file mode 100644 index 0000000..fa7c92e Binary files /dev/null and b/content/projects/gerbolyze/pics/fr4_comparison2.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg new file mode 100644 index 0000000..f8d6397 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_01_small.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg new file mode 100644 index 0000000..ba8e984 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_02_small.jpg differ diff --git a/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg b/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg new file mode 100644 index 0000000..1336739 Binary files /dev/null and b/content/projects/gerbolyze/pics/pcbway_sample_03_small.jpg differ diff --git a/content/projects/gerbolyze/pics/process-overview.png b/content/projects/gerbolyze/pics/process-overview.png new file mode 100644 index 0000000..01d3811 Binary files /dev/null and b/content/projects/gerbolyze/pics/process-overview.png differ diff --git a/content/projects/gerbolyze/pics/process-overview.svg b/content/projects/gerbolyze/pics/process-overview.svg new file mode 100644 index 0000000..b21aa70 --- /dev/null +++ b/content/projects/gerbolyze/pics/process-overview.svg @@ -0,0 +1,7230 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + KiCAD/Altium + SVG + Gerber! + + + + + + + + + + + + diff --git a/content/projects/gerbolyze/pics/sample1.jpg b/content/projects/gerbolyze/pics/sample1.jpg new file mode 100644 index 0000000..948da6f Binary files /dev/null and b/content/projects/gerbolyze/pics/sample1.jpg differ diff --git a/content/projects/gerbolyze/pics/sample2.jpg b/content/projects/gerbolyze/pics/sample2.jpg new file mode 100644 index 0000000..ef47bd4 Binary files /dev/null and b/content/projects/gerbolyze/pics/sample2.jpg differ diff --git a/content/projects/gerbolyze/pics/sample3.jpg b/content/projects/gerbolyze/pics/sample3.jpg new file mode 100644 index 0000000..780c080 Binary files /dev/null and b/content/projects/gerbolyze/pics/sample3.jpg differ diff --git a/content/projects/gerbolyze/pics/subtract_example.png b/content/projects/gerbolyze/pics/subtract_example.png new file mode 100644 index 0000000..f8e138a Binary files /dev/null and b/content/projects/gerbolyze/pics/subtract_example.png differ diff --git a/content/projects/gerbolyze/pics/test_svg_readme.svg b/content/projects/gerbolyze/pics/test_svg_readme.svg new file mode 100644 index 0000000..1a0178e --- /dev/null +++ b/content/projects/gerbolyze/pics/test_svg_readme.svg @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + सर्वे मानवाः स्वतन्त्राः समुत्पन्नाः वर्तन्ते अपि च, गौरवदृशा + + + + + لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار + + This is a gerber export test + + diff --git a/content/projects/gerbolyze/pics/test_svg_readme_composited.png b/content/projects/gerbolyze/pics/test_svg_readme_composited.png new file mode 100644 index 0000000..f686e19 Binary files /dev/null and b/content/projects/gerbolyze/pics/test_svg_readme_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_contours_composited.png b/content/projects/gerbolyze/pics/vec_contours_composited.png new file mode 100644 index 0000000..aa826f8 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_contours_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_hexgrid_composited.png b/content/projects/gerbolyze/pics/vec_hexgrid_composited.png new file mode 100644 index 0000000..9578260 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_hexgrid_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_poisson_composited.png b/content/projects/gerbolyze/pics/vec_poisson_composited.png new file mode 100644 index 0000000..e3ac758 Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_poisson_composited.png differ diff --git a/content/projects/gerbolyze/pics/vec_square_composited.png b/content/projects/gerbolyze/pics/vec_square_composited.png new file mode 100644 index 0000000..02a89ea Binary files /dev/null and b/content/projects/gerbolyze/pics/vec_square_composited.png differ diff --git a/content/projects/gerbonara/index.rst b/content/projects/gerbonara/index.rst new file mode 100644 index 0000000..be28fb4 --- /dev/null +++ b/content/projects/gerbonara/index.rst @@ -0,0 +1,141 @@ +--- +title: "Gerbonara" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbonara.git" + - name: Issues + url: "https://gitlab.com/gerbolyze/gerbonara/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/gerbonara" + - name: PyPI + url: "https://pypi.org/projects/gerbonara" +summary: > + 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. +--- + +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!. + +Gerbonara's API is built on two principles: + +**Meaningful, object-oriented API** + 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 `primitives.Line`, + `primitives.Arc`, or `Region` 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. `GerberFile` and + `ExcellonFile` use the same types of `graphic objects `, so objects can be directly + copied between file types without conversion. + +**Unit-safety** + Gerbonara embeds physical `LengthUnit` information in all objects. The high-level API such as + `LayerStack.merge` or `GerberFile.offset` accepts arguments with an explicitly given unit and + automatically converts them as needed. Objects can be copied between `GerberFile` instances and unit + conversion will be handled transparently in the background. + +Gerbonara was started as an extensive refactoring of the pcb-tools_ and pcb-tools-extension_ 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 *hard*. + +Gerbonara powers gerbolyze_, a tool for converting SVG_ vector graphics files into Gerber, and embedding SVG_ into +existing Gerber files exported from a normal PCB tool for artistic purposes. + +Features +======== + + * File I/O + * Gerber, Excellon (drill file), IPC-356 (netlist) read and write + * supports file-level operations: offset, rotate, merge for all file types + * Modification API (`GraphicObject`) + * Rendering API (`GraphicPrimitive`) + * SVG export + * Full aperture macro support, including transformations (offset, rotation) + +Quick Start +=========== + +First, install gerbonara from PyPI using pip: + +.. code-block:: shell + + pip install --user gerbonara + +Then, you are ready to read and write gerber files: + +.. code-block:: python + + from gerbonara import LayerStack + + stack = LayerStack.from_directory('output/gerber') + w, h = stack.outline.size('mm') + print(f'Board size is {w:.1f} mm x {h:.1f} mm') + +Command-Line Interface +====================== + +Gerbonara comes with a `built-in command-line interface` that has functions for analyzing, rendering, +modifying, and merging Gerber files. To access it, use either the ``gerbonara`` command that is part of the python +package, or run ``python -m gerbonara`` For a list of functions or help on their usage, you can use: + +.. code:: console + + $ python -m gerbonara --help + [...] + $ python -m gerbonara render --help + +Development +=========== + +Gerbonara is developed on Gitlab under the gerbolyze org: + +https://gitlab.com/gerbolyze/gerbonara/ + +A mirror of the repository can be found at: + +https://git.jaseg.de/gerbonara + +Our issue tracker is also on Gitlab: + +https://gitlab.com/gerbolyze/gerbonara/-/issues + +The documentation can be found at gitlab: + +https://gerbolyze.gitlab.io/gerbonara/ + +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. + +Supported CAD Tools +=================== + +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. + + * Allegro + * Altium + * Diptrace + * Eagle + * EasyEDA + * Fritzing + * gEDA + * KiCAD + * pcb-rnd + * Siemens / Mentor Graphics Xpedition + * Siemens PADS + * Target 3001! + * Upverter + * Zuken CR-8000 + +.. _pcb-tools: https://github.com/opiopan/pcb-tools-extension +.. _pcb-tools-extension: https://github.com/curtacircuitos/pcb-tools/issues +.. _gerbolyze: https://github.com/jaseg/gerbolyze +.. _SVG: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics + diff --git a/content/projects/lolcat-c/LOLCat-Rainbow.jpg b/content/projects/lolcat-c/LOLCat-Rainbow.jpg new file mode 100644 index 0000000..9524d26 Binary files /dev/null and b/content/projects/lolcat-c/LOLCat-Rainbow.jpg differ diff --git a/content/projects/lolcat-c/index.rst b/content/projects/lolcat-c/index.rst new file mode 100644 index 0000000..6217b34 --- /dev/null +++ b/content/projects/lolcat-c/index.rst @@ -0,0 +1,105 @@ +--- +title: "lolcat-c" +external_links: + - name: Sources + url: "https://git.jaseg.de/lolcat.git" + - name: Issues + url: "https://github.com/jaseg/lolcat/issues" +summary: > + lolcat-c is a small, high-performance re-implementation of the + `lolcat `__ + 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. +--- + +What? +===== + +.. image:: LOLCat-Rainbow.jpg + +Screenshot +========== + +.. image:: screenshot.png + +.. image:: sl.gif + +Installation +============ + +Archlinux +--------- + +There's an `AUR package `__: + +.. code:: sh + + $ git clone https://aur.archlinux.org/packages/c-lolcat + $ cd c-lolcat + $ makepkg -csi + +Fedora +------ + +.. code:: sh + + $ dnf install lolcat + +Ubuntu (Snap) +------------- + +See `this awesome blog post by a kind person from the internet `__: + +.. code:: sh + + $ snap install lolcat-c + +Mac +--- + +Build loclcat with: + +.. code:: sh + + $ make lolcat + +...and put the resulting binary at a place of your choice. + +Others +------ + +.. code:: sh + + $ make && sudo make install + +Why? +==== + +This `lolcat` 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. + +.. code:: sh + + newton~/d/lolcat <3 dmesg>foo + newton~/d/lolcat <3 time upstream/bin/lolcat foo + 13.51user 1.34system 0:15.99elapsed 92%CPU (0avgtext+0avgdata 10864maxresident)k + 0inputs+0outputs (0major+1716minor)pagefaults 0swaps + newton~/d/lolcat <3 time ./lolcat foo + 0.02user 0.00system 0:00.09elapsed 34%CPU (0avgtext+0avgdata 1936maxresident)k + 0inputs+0outputs (0major+117minor)pagefaults 0swaps + +Bonus comparison with `python-lolcat `__: + +.. code:: sh + + newton~/d/lolcat <3 dmesg>foo + $ time python-lolcat foo + 12.27user 0.00system 0:12.29elapsed 99%CPU (0avgtext+0avgdata 11484maxresident)k + 0inputs+0outputs (0major+1627minor)pagefaults 0swaps + $ time c-lolcat foo + 0.29user 0.00system 0:00.30elapsed 98%CPU (0avgtext+0avgdata 468maxresident)k + 0inputs+0outputs (0major+21minor)pagefaults 0swaps + +(Read: `c-lolcat << python-lolcat << ruby-lolcat`) + + diff --git a/content/projects/lolcat-c/screenshot.png b/content/projects/lolcat-c/screenshot.png new file mode 100644 index 0000000..56282af Binary files /dev/null and b/content/projects/lolcat-c/screenshot.png differ diff --git a/content/projects/lolcat-c/sl.gif b/content/projects/lolcat-c/sl.gif new file mode 100644 index 0000000..9d994e8 Binary files /dev/null and b/content/projects/lolcat-c/sl.gif differ diff --git a/content/projects/python-mpv/README.rst b/content/projects/python-mpv/README.rst new file mode 100644 index 0000000..26815d1 --- /dev/null +++ b/content/projects/python-mpv/README.rst @@ -0,0 +1,401 @@ +.. vim: tw=120 sw=4 et + +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. + +Installation +------------ + +.. code:: bash + + pip install mpv + + +...though you can also realistically just copy `mpv.py`_ into your project as it's all nicely contained in one file. + +Requirements +~~~~~~~~~~~~ + +libmpv +...... +``libmpv.so`` either locally (in your current working directory) or somewhere in your system library search path. This +module is somewhat lenient as far as ``libmpv`` versions are concerned but since ``libmpv`` 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 `issue`_ or +submit a `pull request`_ on github. + +On Windows you can place libmpv anywhere in your ``%PATH%`` (e.g. next to ``python.exe``) or next to this module's +``mpv.py``. 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 `this stackoverflow post +`__ for details. + +Python >= 3.7 (officially) +.......................... +The ``main`` branch officially only supports recent python releases (3.5 onwards), but there is the somewhat outdated +but functional `py2compat branch`_ providing Python 2 compatibility. + +.. _`py2compat branch`: https://github.com/jaseg/python-mpv/tree/py2compat +.. _`issue`: https://github.com/jaseg/python-mpv/issues +.. _`pull request`: https://github.com/jaseg/python-mpv/pulls + +Supported Platforms +................... + +**Linux**, **Windows** and **OSX** all seem to work mostly fine. For some notes on the installation on Windows see +`this comment`__. 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 `issue 36`_ and `issue 61`_ 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. + +.. __: https://github.com/jaseg/python-mpv/issues/60#issuecomment-352719773 +.. _`issue 61`: https://github.com/jaseg/python-mpv/issues/61 +.. _`issue 36`: https://github.com/jaseg/python-mpv/issues/36 + +Usage +----- + +.. code:: python + + import mpv + player = mpv.MPV(ytdl=True) + player.play('https://youtu.be/DOmdB7D-pUU') + player.wait_for_playback() + +python-mpv mostly exposes mpv's built-in API to python, adding only some porcelain on top. Most "`input commands `_" are mapped to methods of the MPV class. Check out these methods and their docstrings in `the source `__ for things you can do. Additional controls and status information are exposed through `MPV properties `_. These can be accessed like ``player.metadata``, ``player.fullscreen`` and ``player.loop_playlist``. + +Threading +~~~~~~~~~ + +The ``mpv`` 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. + +If you want to handle threading yourself, you can pass ``start_event_thread=False`` to the ``MPV`` constructor and +manually call the ``MPV`` object's ``_loop`` 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 ``libmpv`` +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. + +All API functions are thread-safe. If one is not, please file an issue on github. + +Advanced Usage +~~~~~~~~~~~~~~ + +Logging, Properties, Python Key Bindings, Screenshots and youtube-dl +.................................................................... + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + def my_log(loglevel, component, message): + print('[{}] {}: {}'.format(loglevel, component, message)) + + player = mpv.MPV(log_handler=my_log, ytdl=True, input_default_bindings=True, input_vo_keyboard=True) + + # Property access, these can be changed at runtime + @player.property_observer('time-pos') + def time_observer(_name, value): + # Here, _value is either None if nothing is playing or a float containing + # fractional seconds since the beginning of the file. + print('Now playing at {:.2f}s'.format(value)) + + player.fullscreen = True + player.loop_playlist = 'inf' + # Option access, in general these require the core to reinitialize + player['vo'] = 'gpu' + + @player.on_key_press('q') + def my_q_binding(): + print('THERE IS NO ESCAPE') + + @player.on_key_press('s') + def my_s_binding(): + pillow_img = player.screenshot_raw() + pillow_img.save('screenshot.png') + + player.play('https://youtu.be/DLzxrzFCyOs') + player.wait_for_playback() + + del player + +Skipping silence using libav filters +.................................... + +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! + +.. code:: python + + #!/usr/bin/env python3 + import sys + import mpv + + p = mpv.MPV() + p.play(sys.argv[1]) + + def skip_silence(): + p.set_loglevel('debug') + p.af = 'lavfi=[silencedetect=n=-20dB:d=1]' + p.speed = 100 + def check(evt): + toks = evt['event']['text'].split() + if 'silence_end:' in toks: + return float(toks[2]) + p.time_pos = p.wait_for_event('log_message', cond=check) + p.speed = 1 + p.af = '' + + skip_silence() + p.wait_for_playback() + +Video overlays +.............. + +.. code:: python + + #!/usr/bin/env python3 + import time + from PIL import Image, ImageDraw, ImageFont + import mpv + + player = mpv.MPV() + + player.loop = True + player.play('test.webm') + player.wait_until_playing() + + font = ImageFont.truetype('DejaVuSans.ttf', 40) + + while not player.core_idle: + + time.sleep(0.5) + overlay = player.create_image_overlay() + + for pos in range(0, 500, 5): + ts = player.time_pos + if ts is None: + break + + img = Image.new('RGBA', (400, 150), (255, 255, 255, 0)) + d = ImageDraw.Draw(img) + d.text((10, 10), 'Hello World', font=font, fill=(0, 255, 255, 128)) + d.text((10, 60), f't={ts:.3f}', font=font, fill=(255, 0, 255, 255)) + + overlay.update(img, pos=(2*pos, pos)) + time.sleep(0.05) + + overlay.remove() + + +Playlist handling +................. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV(ytdl=True, input_default_bindings=True, input_vo_keyboard=True) + + player.playlist_append('https://youtu.be/PHIGke6Yzh8') + player.playlist_append('https://youtu.be/Ji9qSuQapFY') + player.playlist_append('https://youtu.be/6f78_Tf4Tdk') + + player.playlist_pos = 0 + + while True: + # To modify the playlist, use player.playlist_{append,clear,move,remove}. player.playlist is read-only + print(player.playlist) + player.wait_for_playback() + +Directly feeding mpv data from python +..................................... + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + @player.python_stream('foo') + def reader(): + with open('test.webm', 'rb') as f: + while True: + yield f.read(1024*1024) + + player.play('python://foo') + player.wait_for_playback() + +Using external subtitles +........................ + +The easiest way to load custom subtitles from a file is to pass the ``--sub-file`` option to the ``loadfile`` call: + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + player.loadfile('test.webm', sub_file='test.srt') + player.wait_for_playback() + +Note that you can also pass many other options to ``loadfile``. See the mpv docs for details. + +If you want to add subtitle files or streams at runtime, you can use the ``sub-add`` command. ``sub-add`` 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 +``core-idle`` property. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + + player = mpv.MPV() + player.play('test.webm') + player.wait_until_playing() + player.sub_add('test.srt') + player.wait_for_playback() + +Using MPV's built-in GUI +........................ + +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 `Issue 102`_ for more details + +.. _`issue 102`: https://github.com/jaseg/python-mpv/issues/61 + +.. code:: python + + # Enable the on-screen controller and keyboard shortcuts + player = mpv.MPV(input_default_bindings=True, input_vo_keyboard=True, osc=True) + + # Alternative version using the old "floating box" style on-screen controller + player = mpv.MPV(player_operation_mode='pseudo-gui', + script_opts='osc-layout=box,osc-seekbarstyle=bar,osc-deadzonesize=0,osc-minmousemove=3', + input_default_bindings=True, + input_vo_keyboard=True, + osc=True) + +PyQT embedding +.............. + +.. code:: python + + #!/usr/bin/env python3 + import mpv + import sys + + from PyQt5.QtWidgets import * + from PyQt5.QtCore import * + + class Test(QMainWindow): + def __init__(self, parent=None): + super().__init__(parent) + self.container = QWidget(self) + self.setCentralWidget(self.container) + self.container.setAttribute(Qt.WA_DontCreateNativeAncestors) + self.container.setAttribute(Qt.WA_NativeWindow) + player = mpv.MPV(wid=str(int(self.container.winId())), + vo='x11', # You may not need this + log_handler=print, + loglevel='debug') + player.play('test.webm') + + app = QApplication(sys.argv) + + # This is necessary since PyQT stomps over the locale settings needed by libmpv. + # This needs to happen after importing PyQT before creating the first mpv.MPV instance. + import locale + locale.setlocale(locale.LC_NUMERIC, 'C') + win = Test() + win.show() + sys.exit(app.exec_()) + +PyGObject embedding +................... + +.. code:: python + + #!/usr/bin/env python3 + import gi + + import mpv + + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk + + + class MainClass(Gtk.Window): + + def __init__(self): + super(MainClass, self).__init__() + self.set_default_size(600, 400) + self.connect("destroy", self.on_destroy) + + widget = Gtk.Frame() + self.add(widget) + self.show_all() + + # Must be created >after< the widget is shown, else property 'window' will be None + self.mpv = mpv.MPV(wid=str(widget.get_property("window").get_xid())) + self.mpv.play("test.webm") + + def on_destroy(self, widget, data=None): + self.mpv.terminate() + Gtk.main_quit() + + + if __name__ == '__main__': + # This is necessary since like Qt, Gtk stomps over the locale settings needed by libmpv. + # Like with Qt, this needs to happen after importing Gtk but before creating the first mpv.MPV instance. + import locale + locale.setlocale(locale.LC_NUMERIC, 'C') + + application = MainClass() + Gtk.main() + +Using OpenGL from PyGObject +........................... + +Just like it is possible to render into a GTK widget through X11 windows, it `also is possible to render into a GTK +widget using OpenGL `__ through this python API. + +Using OpenGL from PyQt5/QML +........................... + +Robozman_ has mangaed to `make mpv render into a PyQt5/QML widget using OpenGL +`__ through this python API. + +Using mpv inside imgui inside OpenGL via GLFW +............................................. + +dfaker_ has written a demo (`link `__) that uses mpv to render video into an `imgui `__ UI running on an OpenGL context inside `GLFW `__. 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. + +Running tests +------------- + +Use pytest to run tests. + +Coding Conventions +------------------ + +The general aim is `PEP 8`_, 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 *really* helps readability or it +*really* irks you if you don't. + +License +------- + +python-mpv inherits the underlying libmpv's license, which can be either GPLv2 or later (default) or LGPLv2.1 or later. +For details, see `the mpv copyright page`_. + +.. _`PEP 8`: https://www.python.org/dev/peps/pep-0008/ +.. _`mpv.py`: https://raw.githubusercontent.com/jaseg/python-mpv/main/mpv.py +.. _cosven: https://github.com/cosven +.. _Robozman: https://gitlab.com/robozman +.. _dfaker: https://github.com/dfaker +.. _`the mpv copyright page`: https://github.com/mpv-player/mpv/blob/master/Copyright + diff --git a/content/projects/python-mpv/index.rst b/content/projects/python-mpv/index.rst new file mode 100644 index 0000000..a1bdcd5 --- /dev/null +++ b/content/projects/python-mpv/index.rst @@ -0,0 +1,18 @@ +--- +title: "python-mpv" +external_links: + - name: Sources + url: "https://git.jaseg.de/python-mpv.git" + - name: Issues + url: "https://github.com/jaseg/python-mpv/issues" + - name: Docs + url: "https://neinseg.gitlab.io/python-mpv" + - name: PyPI + url: "https://pypi.org/projects/mpv" +summary: > + 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. +--- + +.. include:: content/projects/python-mpv/README.rst diff --git a/content/projects/svg-flatten/index.rst b/content/projects/svg-flatten/index.rst new file mode 100644 index 0000000..1554bcf --- /dev/null +++ b/content/projects/svg-flatten/index.rst @@ -0,0 +1,15 @@ +--- +title: "svg-flatten" +external_links: + - name: Sources + url: "https://git.jaseg.de/gerbolyze.git/tree/svg-flatten?h=main" + - name: Issues + url: "https://github.com/jaseg/gerbolyze/issues" + - name: Docs + url: "https://gerbolyze.gitlab.io/svg-flatten" +summary: > + 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. +--- + diff --git a/content/projects/wsdiff/index.rst b/content/projects/wsdiff/index.rst new file mode 100644 index 0000000..8c2a7bc --- /dev/null +++ b/content/projects/wsdiff/index.rst @@ -0,0 +1,63 @@ +--- +title: "wsdiff" +external_links: + - name: Sources + url: "https://git.jaseg.de/wsdiff.git" + - name: Issues + url: "https://github.com/jaseg/wsdiff/issues" + - name: Docs + url: "https://pypi.org/projects/wsdiff" +summary: > + 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. +--- + +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. + +Installation +============ + +.. code:: sh + + $ pip install wsdiff + +Usage +===== + +:: + + usage: wsdiff [-h] [-b] [-s SYNTAX_CSS] [-l LEXER] [-L] [-t PAGETITLE] + [-o OUTPUT] [--header] [--content] + [old] [new] + + Given two source files or directories this application creates an html page + that highlights the differences between the two. + + positional arguments: + old source file or directory to compare ("before" file) + new source file or directory to compare ("after" file) + + options: + -h, --help show this help message and exit + -b, --open Open output file in a browser + -s SYNTAX_CSS, --syntax-css SYNTAX_CSS + Path to custom Pygments CSS file for code syntax + highlighting + -l LEXER, --lexer LEXER + Manually select pygments lexer (default: guess from + filename, use -L to list available lexers.) + -L, --list-lexers List available lexers for -l/--lexer + -t PAGETITLE, --pagetitle PAGETITLE + Override page title of output HTML file + -o OUTPUT, --output OUTPUT + Name of output file (default: stdout) + --header Only output HTML header with stylesheets and stuff, + and no diff + --content Only output HTML content, without header + +Example Output +============== + +.. image:: latest.png diff --git a/content/projects/wsdiff/latest.png b/content/projects/wsdiff/latest.png new file mode 100644 index 0000000..039fa46 Binary files /dev/null and b/content/projects/wsdiff/latest.png differ -- cgit