diff options
-rw-r--r-- | gerboweb/gerboweb.py | 14 | ||||
-rw-r--r-- | gerboweb/static/sample2.jpg | bin | 251440 -> 521032 bytes | |||
-rw-r--r-- | gerboweb/templates/index.html | 274 |
3 files changed, 144 insertions, 144 deletions
diff --git a/gerboweb/gerboweb.py b/gerboweb/gerboweb.py index 2633e7b..c227e63 100644 --- a/gerboweb/gerboweb.py +++ b/gerboweb/gerboweb.py @@ -72,7 +72,7 @@ def index(): r = make_response(render_template('index.html', has_renders = path.isfile(tempfile_path('gerber.zip')), - has_output = path.isfile(tempfile_path('overlay.png')), + has_output = path.isfile(tempfile_path('overlay.svg')), **forms)) if 'vector_job' in session or 'render_job' in session: r.headers.set('refresh', '10') @@ -108,7 +108,7 @@ def upload_gerber(): session['filename'] = secure_filename(f.filename) # Cache filename for later download render() - if path.isfile(tempfile_path('overlay.png')): # Re-vectorize when gerbers change + if path.isfile(tempfile_path('overlay.svg')): # Re-vectorize when gerbers change vectorize() flash(f'Gerber file successfully uploaded.', 'success') @@ -121,7 +121,7 @@ def upload_overlay(): if upload_form.validate_on_submit(): # FIXME raise error when no side selected f = upload_form.upload_file.data - f.save(tempfile_path('overlay.png')) + f.save(tempfile_path('overlay.svg')) session['side_selected'] = upload_form.side.data vectorize() @@ -133,7 +133,7 @@ def upload_overlay(): def render_preview(side): if not side in ('top', 'bottom'): return abort(400, 'side must be either "top" or "bottom"') - return send_file(tempfile_path(f'render_{side}.small.png')) + return send_file(tempfile_path(f'template_{side}.preview.png')) @app.route('/render/download/<side>') def render_download(side): @@ -141,10 +141,10 @@ def render_download(side): return abort(400, 'side must be either "top" or "bottom"') session['last_download'] = side - return send_file(tempfile_path(f'render_{side}.png'), - mimetype='image/png', + return send_file(tempfile_path(f'template_{side}.svg'), + mimetype='image/svg', as_attachment=True, - attachment_filename=f'{path.splitext(session["filename"])[0]}_render_{side}.png') + attachment_filename=f'{path.splitext(session["filename"])[0]}_template_{side}.svg') @app.route('/output/download') def output_download(): diff --git a/gerboweb/static/sample2.jpg b/gerboweb/static/sample2.jpg Binary files differindex ef47bd4..ba8e984 100644 --- a/gerboweb/static/sample2.jpg +++ b/gerboweb/static/sample2.jpg diff --git a/gerboweb/templates/index.html b/gerboweb/templates/index.html index a19fc88..3de8ea5 100644 --- a/gerboweb/templates/index.html +++ b/gerboweb/templates/index.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html lang="en"> <head> - <title>Gerbolyze Raster image to PCB renderer</title> + <title>Gerbolyze Image to PCB Toolchain</title> <link rel="stylesheet" type="text/css" href="{{url_for('static', filename='style.css')}}"> <link rel="icon" type="image/png" href="{{url_for('static', filename='favicon-512.png')}}"> <link rel="apple-touch-icon" href="{{url_for('static', filename='favicon-512.png')}}"> @@ -10,157 +10,157 @@ <body> <div class="layout-container"> <div class="header"> - <div class="desc"> - <h1>Raster image to PCB converter</h1> - <p> - Gerbolyze is a tool for rendering black and white raster (PNG) images directly onto gerber layers. You can - use this to put art on a PCB's silkscreen, solder mask or copper layers. The input is a black-and-white PNG - image that is vectorized and rendered into an existing gerber file. Gerbolyze works with gerber files - produced with any EDA toolchain and has been tested to work with both Altium and KiCAD. - </p> - </div> + <div class="desc"> + <h1>SVG/JPG/PNG to PCB converter</h1> + <p> + Gerbolyze is a tool for rendering arbitrary vector (SVG) and raster (PNG/JPG) images directly onto gerber layers. + You can use this to put art on a PCB's silkscreen, solder mask or copper layers. The input is an SVG file + generated from a template. This SVG file has one layer for each PCB layer and the layers are rendered one by one + into the existing gerber file. SVG primitives are converted as-is with (almost) full SVG support, and bitmap + images are vectorized using a vector halftone processor. Gerbolyze works with gerber files produced with any EDA + toolchain and has been tested to work with both Altium and KiCAD. + </p> + </div> </div> {% with messages = get_flashed_messages(with_categories=True) %} - {% if messages %} - <div class="flashes"> - {% for category, message in messages %} - <div class="flash flash-{{category}}">{{ message }}</div> - {% endfor %} - </div> - {% endif %} + {% if messages %} + <div class="flashes"> + {% for category, message in messages %} + <div class="flash flash-{{category}}">{{ message }}</div> + {% endfor %} + </div> + {% endif %} {% endwith %} <form id="reset-form" method="POST" action="{{url_for('session_reset')}}" class="reset-form">{{reset_form.csrf_token}}</form> <div class="steps"> - <div class="step" id="step1"> - <div class="description"> - <h2>Upload zipped gerber files</h2> - <p> - First, upload a zip file containing all your gerber files. The default file names used by KiCAD, Eagle - and Altium are supported. - </p> - </div> + <div class="step" id="step1"> + <div class="description"> + <h2>Upload zipped gerber files</h2> + <p> + First, upload a zip file containing all your gerber files. The default file names used by KiCAD, Eagle + and Altium are supported. + </p> + </div> - <div class="controls"> - <form id="gerber-upload-form" method="POST" action="{{url_for('upload_gerber')}}" enctype="multipart/form-data"> - {{gerber_form.csrf_token}} - </form> - <div class="form-controls"> - <div class="upload-label">Upload Gerber file:</div> - <input class='upload-button' form="gerber-upload-form" name="upload_file" size="20" type="file"> - </div> - <div class="submit-buttons"> - <input class='reset-button' form="reset-form" type="submit" value="Start over"> - <input class='submit-button' form="gerber-upload-form" type="submit" value="Submit"> - </div> - </div> - </div> + <div class="controls"> + <form id="gerber-upload-form" method="POST" action="{{url_for('upload_gerber')}}" enctype="multipart/form-data"> + {{gerber_form.csrf_token}} + </form> + <div class="form-controls"> + <div class="upload-label">Upload Gerber file:</div> + <input class='upload-button' form="gerber-upload-form" name="upload_file" size="20" type="file"> + </div> + <div class="submit-buttons"> + <input class='reset-button' form="reset-form" type="submit" value="Start over"> + <input class='submit-button' form="gerber-upload-form" type="submit" value="Submit"> + </div> + </div> + </div> - {% if 'render_job' in session or has_renders %} - <div class="step" id="step2"> - <div class="description"> - <h2>Download the target side's preview image</h2> - <p> - Second, download either the top or bottom preview image and use it to align and scale your own artwork - in an image editing program such as Gimp. Then upload your overlay image below. + {% if 'render_job' in session or has_renders %} + <div class="step" id="step2"> + <div class="description"> + <h2>Download the target side's preview image</h2> + <p> + Second, download either the top or bottom SVG template and place your own artwork in it on the appropriate + layers. The template is made to work well with the excellent open-source <a href="https://inkscape.org">Inkscape</a> + vector graphics editor. When you are done, upload your overlay below. - Note that you will have to convert grayscale images into binary images yourself. Gerbolyze can't do this - for you since there are lots of variables involved. Our <a href="https://github.com/jaseg/gerbolyze/blob/master/README.rst#image-preprocessing-guide">Guideline on image processing</a> gives an overview on - <i>one</i> way to produce agreeable binary images from grayscale source material. - </p> - </div> - <div class="controls"> - {% if 'render_job' in session %} - <div class="loading-message"> - <div class="lds-ring"><div></div><div></div><div></div><div></div></div> - <div><strong>Processing...</strong></div> - <div>(this may take several minutes!)</div> - </div> - {% else %} - <div class="preview-images"> - <a href="{{url_for('render_download', side='top')}}" onclick="document.querySelector('#side-0').checked=true" class="preview preview-top" style="background-image:url('{{url_for('render_preview', side='top')}}');"> - <div class="overlay">top</div> - </a> - <a href="{{url_for('render_download', side='bottom')}}" onclick="document.querySelector('#side-1').checked=true" class="preview preview-bottom" style="background-image:url('{{url_for('render_preview', side='bottom')}}');"> - <div class="overlay">bot<br/>tom</div> - </a> - </div> - {% endif %} - <div class="submit-buttons"> - <input class='reset-button' form="reset-form" type="submit" value="Start over"> - </div> - </div> - </div> + If you wish to put a bitmap image (PNG/JPG) on your board, simply place it into the SVG on the appropriate + layer. Make sure you select Inkscape's "embed image" option when importing it. + </p> + </div> + <div class="controls"> + {% if 'render_job' in session %} + <div class="loading-message"> + <div class="lds-ring"><div></div><div></div><div></div><div></div></div> + <div><strong>Processing...</strong></div> + <div>(this may take several minutes!)</div> + </div> + {% else %} + <div class="preview-images"> + <a href="{{url_for('render_download', side='top')}}" onclick="document.querySelector('#side-0').checked=true" class="preview preview-top" style="background-image:url('{{url_for('render_preview', side='top')}}');"> + <div class="overlay">top</div> + </a> + <a href="{{url_for('render_download', side='bottom')}}" onclick="document.querySelector('#side-1').checked=true" class="preview preview-bottom" style="background-image:url('{{url_for('render_preview', side='bottom')}}');"> + <div class="overlay">bot<br/>tom</div> + </a> + </div> + {% endif %} + <div class="submit-buttons"> + <input class='reset-button' form="reset-form" type="submit" value="Start over"> + </div> + </div> + </div> - <div class="step" id="step3"> - <div class="description"> - <h2>Upload overlay image</h2> - <p> - Now, upload your binary overlay image as a PNG and let gerbolyze render it onto the target layer. The PNG - file should be a black and white binary file with details generally above about 10px size. <b>Antialiased - edges are supported.</b> - </p> - </div> - <div class="controls"> - <form id="overlay-upload-form" method="POST" action="{{url_for('upload_overlay')}}" enctype="multipart/form-data"> - {{overlay_form.csrf_token}} - </form> - <div class="form-controls"> - <div class="form-label upload-label">Upload Overlay PNG file:</div> - <input class='upload-button' form="overlay-upload-form" name="upload_file" size="20" type="file"> - </div> - <div class="form-controls"> - <div class="form-label target-label">Target layer:</div> - <input form="overlay-upload-form" name="side" id="side-0" type="radio" value="top"> - <label for="side-0">Top</label> - <input form="overlay-upload-form" name="side" id="side-1" type="radio" value="top"> - <label for="side-1">Bottom</label> - </div> - <div class="submit-buttons"> - <input class='reset-button' form="reset-form" type="submit" value="Start over"> - <input class='submit-button' form="overlay-upload-form" type="submit" value="Submit"> - </div> - </div> - </div> + <div class="step" id="step3"> + <div class="description"> + <h2>Upload overlay SVG</h2> + <p> + Now, upload your binary overlay as an SVG and let gerbolyze paste it onto the target layers. + </p> + </div> + <div class="controls"> + <form id="overlay-upload-form" method="POST" action="{{url_for('upload_overlay')}}" enctype="multipart/form-data"> + {{overlay_form.csrf_token}} + </form> + <div class="form-controls"> + <div class="form-label upload-label">Upload Overlay PNG file:</div> + <input class='upload-button' form="overlay-upload-form" name="upload_file" size="20" type="file"> + </div> + <div class="form-controls"> + <div class="form-label target-label">Target layer:</div> + <input form="overlay-upload-form" name="side" id="side-0" type="radio" value="top"> + <label for="side-0">Top</label> + <input form="overlay-upload-form" name="side" id="side-1" type="radio" value="top"> + <label for="side-1">Bottom</label> + </div> + <div class="submit-buttons"> + <input class='reset-button' form="reset-form" type="submit" value="Start over"> + <input class='submit-button' form="overlay-upload-form" type="submit" value="Submit"> + </div> + </div> + </div> - {% if 'vector_job' in session or has_output %} - <div class="step" id="step4"> - <div class="description"> - <h2>Download the processed gerber files</h2> - </div> - <div class="controls"> - {% if 'vector_job' in session %} - <div class="loading-message"> - <div class="lds-ring"><div></div><div></div><div></div><div></div></div> - <div><strong>Processing...</strong></div> - <div>(this may take several minutes!)</div> - </div> - {% else %} - <div class='download-controls'> - <a class='output-download' href="{{url_for('output_download')}}">Click to download</a> - </div> - {% endif %} - <div class="submit-buttons"> - <input class='reset-button' form="reset-form" type="submit" value="Start over"> - </div> - <!--4>Debug foo</h4> - <div class="loading-message"> - <div class="lds-ring"><div></div><div></div><div></div><div></div></div> - <div><strong>Processing...</strong></div> - <div>(this may take several minutes!)</div> - </div--> - </div> - </div> - {% endif %} {# vector job #} - {% endif %} {# render job #} + {% if 'vector_job' in session or has_output %} + <div class="step" id="step4"> + <div class="description"> + <h2>Download the processed gerber files</h2> + </div> + <div class="controls"> + {% if 'vector_job' in session %} + <div class="loading-message"> + <div class="lds-ring"><div></div><div></div><div></div><div></div></div> + <div><strong>Processing...</strong></div> + <div>(this may take several minutes!)</div> + </div> + {% else %} + <div class='download-controls'> + <a class='output-download' href="{{url_for('output_download')}}">Click to download</a> + </div> + {% endif %} + <div class="submit-buttons"> + <input class='reset-button' form="reset-form" type="submit" value="Start over"> + </div> + <!--4>Debug foo</h4> + <div class="loading-message"> + <div class="lds-ring"><div></div><div></div><div></div><div></div></div> + <div><strong>Processing...</strong></div> + <div>(this may take several minutes!)</div> + </div--> + </div> + </div> + {% endif %} {# vector job #} + {% endif %} {# render job #} </div> <div class="sample-images"> - <h1>Sample images</h1> - <img src="{{url_for('static', filename='sample1.jpg')}}"> - <img src="{{url_for('static', filename='sample2.jpg')}}"> - <img src="{{url_for('static', filename='sample3.jpg')}}"> + <h1>Sample images</h1> + <img src="{{url_for('static', filename='sample1.jpg')}}"> + <img src="{{url_for('static', filename='sample2.jpg')}}"> + <img src="{{url_for('static', filename='sample3.jpg')}}"> </div> </div> </body> |