From 6b4eac36d6ff46881b26a36556a07280ccd69783 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 30 Mar 2019 04:01:03 +0900 Subject: gerboweb: Initial design revision --- gerboweb/deploy/render.sh | 4 +- gerboweb/gerboweb.py | 69 +++++++++++-------- gerboweb/static/bg.jpg | Bin 0 -> 331765 bytes gerboweb/static/bg10.jpg | Bin 0 -> 177533 bytes gerboweb/static/sample1.jpg | Bin 0 -> 299841 bytes gerboweb/static/sample2.jpg | Bin 0 -> 251440 bytes gerboweb/static/sample3.jpg | Bin 0 -> 171160 bytes gerboweb/static/style.css | 149 +++++++++++++++++++++++++++++++++++------- gerboweb/templates/index.html | 63 +++++++++++------- 9 files changed, 207 insertions(+), 78 deletions(-) create mode 100644 gerboweb/static/bg.jpg create mode 100644 gerboweb/static/bg10.jpg create mode 100644 gerboweb/static/sample1.jpg create mode 100644 gerboweb/static/sample2.jpg create mode 100644 gerboweb/static/sample3.jpg (limited to 'gerboweb') diff --git a/gerboweb/deploy/render.sh b/gerboweb/deploy/render.sh index c3920de..eefe7f0 100755 --- a/gerboweb/deploy/render.sh +++ b/gerboweb/deploy/render.sh @@ -13,8 +13,8 @@ rm -f /mnt/render_top.png /mnt/render_bottom.png /mnt/render_top.small.png /mnt/ date; echo 'Rendering bottom layer' gerbolyze render top /tmp/gerber /mnt/render_top.png date; echo 'Scaling down' -convert /mnt/render_top.png -resize 500x500 /mnt/render_top.small.png +convert /mnt/render_top.png -resize 500x500 -negate -brightness-contrast 30x30 -colorspace gray /mnt/render_top.small.png date; echo 'Rendering top layer' gerbolyze render bottom /tmp/gerber /mnt/render_bottom.png date; echo 'Scaling down' -convert /mnt/render_bottom.png -resize 500x500 /mnt/render_bottom.small.png" +convert /mnt/render_bottom.png -resize 500x500 -negate -brightness-contrast 30x30 -colorspace gray /mnt/render_bottom.small.png" diff --git a/gerboweb/gerboweb.py b/gerboweb/gerboweb.py index 1f8d884..a276d74 100644 --- a/gerboweb/gerboweb.py +++ b/gerboweb/gerboweb.py @@ -26,7 +26,8 @@ class UploadForm(FlaskForm): class OverlayForm(UploadForm): upload_file = FileField(validators=[FileRequired()]) - side = RadioField('Side', choices=[('top', 'Top'), ('bottom', 'Bottom')], default=lambda: session.get('last_download')) + side = RadioField('Side', choices=[('top', 'Top'), ('bottom', 'Bottom')], + default=lambda: session.get('side_selected', session.get('last_download'))) class ResetForm(FlaskForm): pass @@ -56,7 +57,6 @@ def require_session_id(fun): @app.route('/') @require_session_id def index(): - flash(f'Gerber file successfully uploaded.', 'success') forms = { 'gerber_form': UploadForm(), 'overlay_form': OverlayForm(), @@ -79,37 +79,49 @@ def index(): # * The uploaded files are deleted after a while by systemd tmpfiles.d # TODO: validate this setting applies *after* gzip transport compression -@app.route('/upload/', methods=['POST']) +def vectorize(): + if 'vector_job' in session: + job_queue.drop(session['vector_job']) + session['vector_job'] = job_queue.enqueue('vector', + client=request.remote_addr, + session_id=session['session_id'], + side=session['side_selected']) + +def render(): + if 'render_job' in session: + job_queue.drop(session['render_job']) + session['render_job'] = job_queue.enqueue('render', + session_id=session['session_id'], + client=request.remote_addr) + +@app.route('/upload/gerber', methods=['POST']) @require_session_id -def upload(namespace): - if namespace not in ('gerber', 'overlay'): - return abort(400, 'Invalid upload type') +def upload_gerber(): + upload_form = UploadForm() + if upload_form.validate_on_submit(): + f = upload_form.upload_file.data + f.save(tempfile_path('gerber.zip')) + session['filename'] = secure_filename(f.filename) # Cache filename for later download - upload_form = UploadForm() if namespace == 'gerber' else OverlayForm() + render() + if path.isfile(tempfile_path('overlay.png')): # Re-vectorize when gerbers change + vectorize() + + flash(f'Gerber file successfully uploaded.', 'success') + return redirect(url_for('index')) + +@app.route('/upload/overlay', methods=['POST']) +@require_session_id +def upload_overlay(): + upload_form = OverlayForm() if upload_form.validate_on_submit(): f = upload_form.upload_file.data + f.save(tempfile_path('overlay.png')) + session['side_selected'] = upload_form.side.data + + vectorize() - if namespace == 'gerber': - f.save(tempfile_path('gerber.zip')) - session['filename'] = secure_filename(f.filename) # Cache filename for later download - if 'render_job' in session: - job_queue.drop(session['render_job']) - session['render_job'] = job_queue.enqueue('render', - session_id=session['session_id'], - client=request.remote_addr) - else: # namespace == 'vector' - f.save(tempfile_path('overlay.png')) - - # Re-vectorize if either file has changed - if path.isfile(tempfile_path('gerber.zip')) and path.isfile(tempfile_path('overlay.png')): - if 'vector_job' in session: - job_queue.drop(session['vector_job']) - session['vector_job'] = job_queue.enqueue('vector', - client=request.remote_addr, - session_id=session['session_id'], - side=upload_form.side.data) - - flash(f'{"Gerber" if namespace == "gerber" else "Overlay"} file successfully uploaded.', 'success') + flash(f'Overlay file successfully uploaded.', 'success') return redirect(url_for('index')) @app.route('/render/preview/') @@ -144,5 +156,6 @@ def session_reset(): if 'vector_job' in session: session['vector_job'].abort() session.clear() + flash('Session reset', 'success'); return redirect(url_for('index')) diff --git a/gerboweb/static/bg.jpg b/gerboweb/static/bg.jpg new file mode 100644 index 0000000..94856fc Binary files /dev/null and b/gerboweb/static/bg.jpg differ diff --git a/gerboweb/static/bg10.jpg b/gerboweb/static/bg10.jpg new file mode 100644 index 0000000..9d14fd3 Binary files /dev/null and b/gerboweb/static/bg10.jpg differ diff --git a/gerboweb/static/sample1.jpg b/gerboweb/static/sample1.jpg new file mode 100644 index 0000000..948da6f Binary files /dev/null and b/gerboweb/static/sample1.jpg differ diff --git a/gerboweb/static/sample2.jpg b/gerboweb/static/sample2.jpg new file mode 100644 index 0000000..ef47bd4 Binary files /dev/null and b/gerboweb/static/sample2.jpg differ diff --git a/gerboweb/static/sample3.jpg b/gerboweb/static/sample3.jpg new file mode 100644 index 0000000..780c080 Binary files /dev/null and b/gerboweb/static/sample3.jpg differ diff --git a/gerboweb/static/style.css b/gerboweb/static/style.css index 975c7f2..ede89d4 100644 --- a/gerboweb/static/style.css +++ b/gerboweb/static/style.css @@ -35,30 +35,61 @@ --cg5: #4cffa4; --cg6: #b7ffda; --cg7: #e1fff0; + + --cr1: #300900; + --cr2: #611200; + --cr3: #961c00; + --cr4: #d12700; + --cr5: #ff6e4c; + --cr6: #ffc5b7; + --cr7: #ffe7e1; + + --cb1: #001b30; + --cb2: #003761; + --cb3: #005596; + --cb4: #0076d1; + --cb5: #4cb1ff; + --cb6: #b7e0ff; + --cb7: #e1f2ff; + --cb8: #f5fbff; } body { font-family: 'Helvetica', 'Arial', sans-serif; - color: var(--c-metallic4); + color: var(--cb1); display: flex; flex-direction: row; justify-content: center; margin: 0; - background-color: hsl(10 10% 97%); + background-color: var(--cb8); } .layout-container { flex-basis: 55em; flex-shrink: 1; flex-grow: 0; - padding: 3em; + padding: 45px; background-color: white; } +div.header { + background-image: url("/static/bg10.jpg"); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + display: flex; + margin-left: -45px; + margin-right: -45px; + margin-bottom: 3em; + padding-left: 3em; + padding-right: 3em; + text-shadow: 1px 1px 1px black; +} + div.flash-success { - background-color: var(--c-green1); - color: hsl(80 20% 20%); - text-shadow: 0 0 2px var(--c-green1); + background-color: var(--cg6); + color: var(--cg1); + text-shadow: 0 0 2px var(--cg7); border-radius: 5px; margin: 1em; padding-left: 3em; @@ -79,6 +110,13 @@ div.flash-success::before { div.desc { margin-top: 5em; margin-bottom: 7em; + + overflow-wrap: break-word; + word-wrap: break-word; + hyphens: auto; + text-align: justify; + + color: white; } div.loading-message { @@ -89,6 +127,7 @@ div.loading-message { .steps { display: flex; flex-direction: column; + counter-reset: step; } .step { @@ -99,6 +138,29 @@ div.loading-message { flex-wrap: wrap; width: 100%; padding-top: 20px; + position: relative; + margin-bottom: 1em; + margin-top: 2em; +} + +.step > .description::before { + counter-increment: step; + content: counter(step); + + font-weight: 700; + font-size: 30px; + text-align: center; + border-radius: 50%; + background-color: var(--cg5); + + display: block; + position: absolute; + top: 15px; + left: 0; + width: 60px; + + line-height: 50px; + padding-top: 10px; } .step > .description { @@ -115,7 +177,9 @@ div.loading-message { .step > .description > h2 { text-align: right; - margin-top: 0 + margin-top: 0; + padding-left: 60px; + height: 60px; } .step > .controls { @@ -124,28 +188,28 @@ div.loading-message { display: flex; flex-direction: column; align-items: stretch; - margin-right: 20px; - margin-left: 20px; + margin-right: 1em; + margin-left: 1em; padding: 1em; - background-color: hsl(210 40% 97%); + background-color: var(--cb8); border-radius: 5px; } input.reset-button { - background-color: var(--c-red1); - color: var(--c-grey1); - text-shadow: 0 0 2px var(--c-red3); + background-color: var(--cr4); + color: white; + text-shadow: 0 0 2px var(--cr1); border: 0; border-radius: 5px; padding: 0.5em 1em 0.5em 1em; } input.submit-button { - background-color: var(--c-green2); - color: hsl(80 20% 20%); - text-shadow: 0 0 2px var(--c-green1); + background-color: var(--cg4); + color: var(--cg1); + text-shadow: 0 0 2px var(--cg7); font-weight: bold; margin-left: 1em; border: 0; @@ -173,8 +237,8 @@ input.submit-button { a.output-download:link, a.output-download:hover, a.output-download:visited, a.output-download:active { font-size: 30pt; font-weight: bold; - color: var(--c-metallic4); - text-shadow: 0.5px 0.5px 0.5px var(--c-metallic2); + color: var(--cb1); + text-shadow: 0.5px 0.5px 0.5px var(--cb6); } .preview-images { @@ -185,21 +249,56 @@ a.output-download:link, a.output-download:hover, a.output-download:visited, a.ou justify-content: space-around; } -.preview { +a.preview:link, a.preview:hover, a.preview:visited, a.preview:active { + text-decoration: none; width: 200px; height: 200px; border-radius: 5px; + margin: 1em; display: flex; justify-content: center; align-items: center; + background-color: var(--cb3); + background-blend-mode: multiply; + background-size: contain; + background-repeat: no-repeat; + background-position: 50% 50%; + box-shadow: 1px 1px 5px 1px #001b304d; } -a.overlay:link, a.overlay:hover, a.overlay:visited, a.overlay:active { +.overlay { text-align: center; - font-size: 30pt; + font-size: 50pt; font-weight: bold; - color: var(--c-metallic4); - text-shadow: 0.5px 0.5px 0.5px var(--c-metallic2); + color: var(--cg4); + mix-blend-mode: screen; +} + +.sample-images { + text-align: center; +} + +.sample-images > h1 { + color: white; + padding-top: 5px; + line-height: 70px; + /* background-image: linear-gradient(to top right, var(--cg5), var(--cg6)); */ + + background-image: url("/static/bg10.jpg"); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + + margin-left: -45px; + margin-right: -45px; + margin-top: 3em; + text-shadow: 1px 1px 1px black; +} + +.sample-images > img { + width: 300px; + height: 300px; + margin: 1em; } /* Spinner from https://loading.io/css/ */ @@ -216,10 +315,10 @@ a.overlay:link, a.overlay:hover, a.overlay:visited, a.overlay:active { width: 51px; height: 51px; margin: 6px; - border: 6px solid var(--c-metallic4); + border: 6px solid var(--cb1); border-radius: 50%; animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; - border-color: var(--c-metallic4) transparent transparent transparent; + border-color: var(--cb1) transparent transparent transparent; } .lds-ring div:nth-child(1) { animation-delay: -0.45s; diff --git a/gerboweb/templates/index.html b/gerboweb/templates/index.html index 3e4c255..eeece65 100644 --- a/gerboweb/templates/index.html +++ b/gerboweb/templates/index.html @@ -6,14 +6,16 @@
-
-

Raster image to PCB converter

-

- 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. -

+
+
+

Raster image to PCB converter

+

+ 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. +

+
{% with messages = get_flashed_messages(with_categories=True) %} @@ -31,7 +33,7 @@
-

Step 1: Upload zipped gerber files

+

Upload zipped gerber files

First, upload a zip file containing all your gerber files. The default file names used by KiCAD, Eagle and Altium are supported. @@ -39,7 +41,7 @@

-
+ {{gerber_form.csrf_token}}
@@ -56,7 +58,7 @@ {% if 'render_job' in session or has_renders %}
-

Step 2: Download the target side's preview image

+

Download the target side's preview image

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. @@ -68,15 +70,19 @@

{% if 'render_job' in session %} - Processing... (this may take several minutes!) +
+
+
Processing...
+
(this may take several minutes!)
+
{% else %} {% endif %}
@@ -87,7 +93,7 @@
-

Step 3: Upload overlay image

+

Upload overlay image

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. Antialiased @@ -95,7 +101,7 @@

-
+ {{overlay_form.csrf_token}}
@@ -119,11 +125,10 @@ {% if 'vector_job' in session or has_output %}
-

Step 4: Download the processed gerber files

+

Download the processed gerber files

- {# if 'vector_job' in session FIXME #} - {% if True %} + {% if 'vector_job' in session %}
Processing...
@@ -137,11 +142,23 @@
+
{% endif %} {# vector job #} {% endif %} {# render job #}
+
+

Sample images

+ + + +
-- cgit