From b31c2b9318e588230c1ee7b199ba7eed1c7fe2d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Mischler=20=28aka=20skarab=29?=
 <skarab@bluewin.ch>
Date: Sun, 20 Mar 2016 17:54:30 +0100
Subject: [PATCH] export slices images as ZIP file

---
 index.html | 26 ++++++++++++++--
 js/main.js | 89 +++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 98 insertions(+), 17 deletions(-)

diff --git a/index.html b/index.html
index 6b4e75b..501b8aa 100644
--- a/index.html
+++ b/index.html
@@ -40,6 +40,12 @@
                     <button id="slice-button" class="btn btn-success" type="button">
                         <span class="glyphicon glyphicon-align-center"></span> Slice
                     </button>
+                    <button id="abort-button" class="btn btn-danger hidden" type="button">
+                        <span class="glyphicon glyphicon-off"></span> Abort
+                    </button>
+                    <button id="zip-button" class="btn btn-info" type="button" disabled="disabled">
+                        <span class="glyphicon glyphicon-compressed"></span> ZIP
+                    </button>
                 </div>
 
                 <div id="file" class="panel panel-default">
@@ -117,13 +123,27 @@ <h3 class="panel-title">Slicer</h3>
                             <input type="number" id="slicer-layers-height" class="form-control input-sm" placeholder="100" min="1" />
                         </div>
                         <div class="form-group">
-                            <label for="slicer-light-on">Light on <small>(ms)</small></label>
+                            <label for="slicer-light-on">Light on delay <small>(ms)</small></label>
                             <input type="number" id="slicer-light-on" class="form-control input-sm" placeholder="1000" min="1" />
                         </div>
                         <div class="form-group">
-                            <label for="slicer-light-off">Light off <small>(ms)</small></label>
+                            <label for="slicer-light-off">Light off delay <small>(ms)</small></label>
                             <input type="number" id="slicer-light-off" class="form-control input-sm" placeholder="500" min="1" />
                         </div>
+                        <div class="form-group">
+                            <label for="slicer-make-zip">Make ZIP file</label>
+                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-yes" value="yes" /> yes
+                            <input type="radio" name="slicer-make-zip" id="slicer-make-zip-no" value="no" checked="checked" /> no
+                        </div>
+                        <div class="form-group">
+                            <label for="slicer-speed">Speed mode</label>
+                            <input type="radio" name="slicer-speed" id="slicer-speed-yes" value="yes" /> yes
+                            <input type="radio" name="slicer-speed" id="slicer-speed-no" value="no" checked="checked" /> no
+                        </div>
+                        <div class="form-group">
+                            <label for="slicer-speed-delay">Speed mode<br />delay <small>(ms)</small></label>
+                            <input type="number" id="slicer-speed-delay" class="form-control input-sm" placeholder="100" min="1" />
+                        </div>
                     </div>
                 </div><!-- #slicer -->
 
@@ -244,6 +264,8 @@ <h3 class="panel-title">Screen</h3>
         <script src="js/slacer/viewer2d.js" type="text/javascript"></script>
         <script src="js/slacer/slicer.js" type="text/javascript"></script>
         <script src="js/loader/stl.js" type="text/javascript"></script>
+        <script src="vendor/FileSaver.min.js" type="text/javascript"></script>
+        <script src="vendor/jszip.min.js" type="text/javascript"></script>
         <script src="js/main.js" type="text/javascript"></script>
     </body>
 </html>
diff --git a/js/main.js b/js/main.js
index 8f2a27e..5789b93 100644
--- a/js/main.js
+++ b/js/main.js
@@ -9,13 +9,6 @@ var settings = new SLAcer.Settings({
             position : 0
         }
     },
-    mesh: {
-        color: 0x333333,
-        panel: {
-            collapsed: false,
-            position : 1
-        }
-    },
     slicer: {
         layers: {
             height: 100 // μm
@@ -24,6 +17,16 @@ var settings = new SLAcer.Settings({
             on : 1000,
             off: 500
         },
+        zip: true,
+        speed: false,
+        speedDelay: 10, // ms
+        panel: {
+            collapsed: false,
+            position : 1
+        }
+    },
+    mesh: {
+        color: 0x333333,
         panel: {
             collapsed: false,
             position : 2
@@ -142,10 +145,16 @@ function getSlice(layerNumber) {
     viewer3d.render();
 
     // render 2D view
-    if (viewer2dWin) {
-        var body = viewer2dWin.document.body;
+    if (zipFolder || viewer2dWin) {
         viewer2d.screenshot(function(dataURL) {
-            body.style.backgroundImage = 'url(' + dataURL + ')';
+            if (viewer2dWin) {
+                viewer2dWin.document.body.style.backgroundImage = 'url(' + dataURL + ')';
+            }
+            if (zipFolder) {
+                var fileName = layerNumber + '.png';
+                var imgData  = dataURL.substr(dataURL.indexOf(',') + 1);
+                zipFolder.file(fileName, imgData, { base64: true });
+            }
         });
     }
 }
@@ -331,10 +340,18 @@ var $slicerLayersValue = $slicerBody.find('#slicer-layers-value');
 var $slicerLayerValue  = $slicerBody.find('#slicer-layer-value');
 var $slicerLightOff    = $slicerBody.find('#slicer-light-off');
 var $slicerLightOn     = $slicerBody.find('#slicer-light-on');
+var $slicerSpeedYes    = $slicerBody.find('#slicer-speed-yes');
+var $slicerSpeedNo     = $slicerBody.find('#slicer-speed-no');
+var $slicerSpeedDelay  = $slicerBody.find('#slicer-speed-delay');
+var $slicerMakeZipYes  = $slicerBody.find('#slicer-make-zip-yes');
+var $slicerMakeZipNo   = $slicerBody.find('#slicer-make-zip-no');
 var $sliceButton       = $sidebar.find('#slice-button');
+var $abortButton       = $sidebar.find('#abort-button');
+var $zipButton         = $sidebar.find('#zip-button');
 
 function updateSlicerUI() {
     var slicer = settings.get('slicer');
+    $slicerSpeedDelay.val(slicer.speedDelay);
     $slicerLayerHeight.val(slicer.layers.height);
     $slicerLightOff.val(slicer.light.off);
     $slicerLightOn.val(slicer.light.on);
@@ -344,6 +361,11 @@ function updateSlicerSettings() {
     settings.set('slicer.layers.height', $slicerLayerHeight.val());
     settings.set('slicer.light.off', $slicerLightOff.val());
     settings.set('slicer.light.on', $slicerLightOn.val());
+
+    settings.set('slicer.zip', $slicerMakeZipYes[0].checked);
+    settings.set('slicer.speed', $slicerSpeedYes[0].checked);
+    settings.set('slicer.speedDelay', $slicerSpeedDelay.val());
+
     updateSliderUI();
 }
 
@@ -351,6 +373,8 @@ var sliceInterval;
 var expectedSliceInterval;
 var currentSliceNumber;
 var slicesNumber;
+var zipFile;
+var zipFolder;
 
 function slice() {
     currentSliceNumber++;
@@ -365,8 +389,8 @@ function slice() {
     var time = Date.now();
     var diff = time - expectedSliceInterval;
 
-    viewer2dWin && setTimeout(function() {
-        viewer2dWin.document.body.style.backgroundImage = 'none';
+    !settings.get('slicer.speed') && viewer2dWin && setTimeout(function() {
+        viewer2dWin && (viewer2dWin.document.body.style.backgroundImage = 'none');
     }, settings.get('slicer.light.on'));
 
     expectedSliceInterval += sliceInterval;
@@ -377,27 +401,62 @@ function endSlicing() {
     viewer2dWin && (viewer2dWin.document.body.style.backgroundImage = 'none');
     $sidebar.find('input, button').prop('disabled', false);
     $sliderInput.slider('enable');
+    $abortButton.addClass('hidden');
+    $sliceButton.removeClass('hidden');
+    $zipButton.prop('disabled', !zipFile);
 }
 
 function startSlicing() {
-    var times             = settings.get('slicer.light');
-    sliceInterval         = parseInt(times.on) + parseInt(times.off);
+    var times = settings.get('slicer.light');
+
+    if (settings.get('slicer.speed')) {
+        sliceInterval = parseInt(settings.get('slicer.speedDelay'));
+    }
+    else {
+        sliceInterval = parseInt(times.on) + parseInt(times.off);
+    }
+
     expectedSliceInterval = Date.now() + sliceInterval;
     slicesNumber          = parseInt($slicerLayersValue.html());
     currentSliceNumber    = 0;
 
+    zipFile   = null;
+    zipFolder = null;
+
+    if (settings.get('slicer.zip')) {
+        zipFile   = new JSZip();
+        zipFolder = zipFile.folder('slices');
+        zipFile.file("README.txt", 'Generated by SLAcer.js\r\nhttp://lautr3k.github.io/SLAcer.js/\r\n');
+    }
+
     slicesNumber && slice();
 }
 
+$zipButton.on('click', function(e) {
+    if (zipFile) {
+        saveAs(zipFile.generate({type: 'blob'}), 'SLAcer.zip');
+    }
+});
+
 $sliceButton.on('click', function(e) {
     $sidebar.find('input, button').prop('disabled', true);
     $('.panel-heading button').prop('disabled', false);
     $openViewer2D.prop('disabled', false);
     $sliderInput.slider('disable');
+    $abortButton.prop('disabled', false);
+    $abortButton.removeClass('hidden');
+    $sliceButton.addClass('hidden');
     startSlicing();
 });
 
-$('#slicer input').on('input', updateSlicerSettings);
+$abortButton.on('click', function(e) {
+    currentSliceNumber = slicesNumber + 1;
+    endSlicing();
+});
+
+$('#slicer-make-zip-' + (settings.get('slicer.zip') ? 'yes' : 'no')).prop('checked', true);
+$('#slicer-speed-' + (settings.get('slicer.speed') ? 'yes' : 'no')).prop('checked', true);
+$('#slicer input').on('input, change', updateSlicerSettings);
 updateSlicerUI();
 
 // Build volume panel
