Initial
This commit is contained in:
333
lib/zpl-image/zpl-image.html
Normal file
333
lib/zpl-image/zpl-image.html
Normal file
@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset=utf-8 />
|
||||
<title>Image to ZPL</title>
|
||||
<style>
|
||||
* {
|
||||
font-family:Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
body, html {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#title {
|
||||
background-color: #404040;
|
||||
color: white;
|
||||
padding: .75ex 2ex;
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
#drop {
|
||||
box-sizing: border-box;
|
||||
width: 480px;
|
||||
height: 90px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
line-height:61px; /* 90/2 + 16 */
|
||||
color: #999;
|
||||
border: 1px dashed #6495ED;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
#drop.droppable {
|
||||
background-color: #fcfeff;
|
||||
color: #87cefa;
|
||||
}
|
||||
|
||||
/* Original and rendered image text labels */
|
||||
.label {
|
||||
color: blue;
|
||||
font-size: 125%;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-left: 10px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Where the dropped and rendered images are displayed */
|
||||
.content {
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
max-width: 600px;
|
||||
max-height: 480px;
|
||||
min-height: 480px;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
}
|
||||
.content > * {
|
||||
box-shadow: 0 0 0 1px blue;
|
||||
}
|
||||
/* Hidden but copy-able */
|
||||
#zpltext {
|
||||
opacity: .01;
|
||||
position: absolute;
|
||||
height: 0px;
|
||||
}
|
||||
table.fields th {
|
||||
padding-left: 4ex;
|
||||
text-align: right;
|
||||
padding-right: 1.5ex;
|
||||
}
|
||||
table.fields th, table.fields td {
|
||||
padding-bottom: 2ex;
|
||||
}
|
||||
/* Labels to the right of the input fields */
|
||||
span {
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-left: 1ex;
|
||||
font-style: italic;
|
||||
}
|
||||
/* Black threshold */
|
||||
input[type="number"] {
|
||||
width: 4em;
|
||||
border: 1px solid #6495ED;
|
||||
border-radius: 3px;
|
||||
padding: 3px .75ex;
|
||||
padding-right: 1px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="copyzpl.css" />
|
||||
<script type="text/javascript" src="pako.js"></script>
|
||||
<script type="text/javascript" src="zpl-image.js"></script>
|
||||
<script type="text/javascript">
|
||||
let _filename = ''; // value set on image drop
|
||||
window.addEventListener('load', function() {
|
||||
document.getElementById('rotN').addEventListener('click', convertImage, false);
|
||||
document.getElementById('rotL').addEventListener('click', convertImage, false);
|
||||
document.getElementById('rotR').addEventListener('click', convertImage, false);
|
||||
document.getElementById('rotI').addEventListener('click', convertImage, false);
|
||||
document.getElementById('black').addEventListener('input', convertImage, false);
|
||||
document.getElementById('notrim').addEventListener('click', convertImage, false);
|
||||
document.getElementById('acscomp').addEventListener('click', convertImage, false);
|
||||
document.getElementById('z64comp').addEventListener('click', convertImage, false);
|
||||
document.getElementById('copyzpl').addEventListener('click', copyZPL, false);
|
||||
|
||||
// Setup the drop target
|
||||
let drop = document.getElementById('drop');
|
||||
|
||||
function candrop(ev) {
|
||||
ev.target.className = 'droppable';
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
}
|
||||
function undrop(ev) {
|
||||
ev.target.className = '';
|
||||
}
|
||||
|
||||
drop.addEventListener('dragover', candrop, false);
|
||||
drop.addEventListener('dragenter', candrop, false);
|
||||
drop.addEventListener('dragleave', undrop, false);
|
||||
|
||||
drop.addEventListener('drop', function (ev) {
|
||||
undrop(ev);
|
||||
ev.preventDefault(); // stop the browser from redirecting
|
||||
|
||||
let xfer = ev.dataTransfer;
|
||||
let files = xfer.files;
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let file = files[0];
|
||||
let reader = new FileReader();
|
||||
|
||||
reader.onloadend = function() {
|
||||
let bin = this.result;
|
||||
let img = document.getElementById('image');
|
||||
|
||||
_filename = file.name;
|
||||
img.src = bin;
|
||||
img.onload = convertImage;
|
||||
|
||||
// Make the img/canvas visible
|
||||
let lbls = document.querySelectorAll('div.label');
|
||||
for (let i = 0; i < lbls.length; i++) {
|
||||
lbls[i].style.visibility = 'visible';
|
||||
}
|
||||
let divs = document.querySelectorAll('div.content');
|
||||
for (let i = 0; i < divs.length; i++) {
|
||||
divs[i].style.visibility = 'visible';
|
||||
}
|
||||
document.getElementById('copyzpl').style.visibility = 'visible';
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
return false;
|
||||
}, false);
|
||||
}, false);
|
||||
function convertImage() {
|
||||
if (!_filename) {
|
||||
return;
|
||||
}
|
||||
let black = +document.getElementById('black').value || 50;
|
||||
let rotrad = document.querySelector('input[name=rot]:checked');
|
||||
let comprad = document.querySelector('input[name=compress]:checked');
|
||||
let rot = rotrad && rotrad.value || 'N';
|
||||
let comp = comprad && comprad.value || 'Z64';
|
||||
let notrim = document.getElementById('notrim').checked;
|
||||
|
||||
// Get the image and convert to Z64
|
||||
let img = document.getElementById('image');
|
||||
let res;
|
||||
let bmp; // actually a canvas object
|
||||
if (comp == 'Z64') {
|
||||
res = imageToZ64(img, { black:black, rotate:rot, notrim:notrim });
|
||||
bmp = z64ToCanvas(res.z64, res.rowlen);
|
||||
} else {
|
||||
res = imageToACS(img, { black:black, rotate:rot, notrim:notrim });
|
||||
bmp = acsToCanvas(res.acs, res.rowlen);
|
||||
}
|
||||
|
||||
// Draw the image to our canvas
|
||||
let cvs = document.getElementById('canvas');
|
||||
cvs.width = bmp.width;
|
||||
cvs.height = bmp.height;
|
||||
cvs.getContext('2d').drawImage(bmp, 0, 0);
|
||||
|
||||
// Create the ZPL with a source comment
|
||||
document.getElementById('zpltext').value =
|
||||
'^FX ' + _filename + ' (' + res.width + 'x' + res.height + 'px, ' +
|
||||
rot + '-Rotate, ' + black + '% Black)^FS\n' +
|
||||
'^GFA,' + res.length + ',' + res.length + ',' + res.rowlen + ',' + (res.z64||res.acs) + '\n';
|
||||
}
|
||||
function copyZPL() {
|
||||
let ta = document.getElementById('zpltext');
|
||||
ta.select();
|
||||
document.execCommand('copy');
|
||||
}
|
||||
function z64ToCanvas(z64, rowl) {
|
||||
// Strip the ':Z64:' prefix and :XXXX crc16 suffix and convert to binary string.
|
||||
// We do not validate the CRC.
|
||||
let bin = atob(z64.substr(5, z64.length - 10));
|
||||
|
||||
// pako wants a Uint8Array
|
||||
let buf = new Uint8Array(bin.length);
|
||||
for (let i = 0, l = bin.length; i < l; i++) {
|
||||
buf[i] = bin.charCodeAt(i);
|
||||
}
|
||||
|
||||
let grf = pako.inflate(buf);
|
||||
let l = grf.length;
|
||||
let w = rowl * 8; // rowl is in bytes
|
||||
let h = ~~(l / rowl);
|
||||
|
||||
// Render the GRF to a canvas
|
||||
let cvs = document.createElement('canvas');
|
||||
cvs.width = w;
|
||||
cvs.height = h;
|
||||
|
||||
let ctx = cvs.getContext('2d');
|
||||
let bmap = ctx.getImageData(0, 0, w, h);
|
||||
let data = bmap.data;
|
||||
let offs = 0;
|
||||
for (let i = 0; i < l; i++) {
|
||||
let byte = grf[i];
|
||||
for (let bit = 0x80; bit; bit = bit >>> 1, offs += 4) {
|
||||
if (bit & byte) {
|
||||
data[offs] = 0;
|
||||
data[offs+1] = 0;
|
||||
data[offs+2] = 0;
|
||||
data[offs+3] = 255; // Fully opaque
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(bmap, 0, 0);
|
||||
return cvs;
|
||||
}
|
||||
function acsToCanvas(acs, rowl) {
|
||||
let hex = acs.replace(/[g-zG-Y]+([0-9a-fA-F])/g, ($0, $1) => {
|
||||
let rep = 0;
|
||||
for (let i = 0, l = $0.length-1; i < l; i++) {
|
||||
let cd = $0.charCodeAt(i);
|
||||
if (cd < 90) { // 'Z'
|
||||
rep += cd - 70;
|
||||
} else {
|
||||
rep += (cd - 102) * 20;
|
||||
}
|
||||
}
|
||||
return $1.repeat(rep);
|
||||
});
|
||||
|
||||
let bytes = Array(hex.length/2);
|
||||
for (let i = 0, l = hex.length; i < l; i += 2) {
|
||||
bytes[i>>1] = parseInt(hex.substr(i,2), 16);
|
||||
}
|
||||
|
||||
let l = bytes.length;
|
||||
let w = rowl * 8; // rowl is in bytes
|
||||
let h = ~~(l / rowl);
|
||||
|
||||
// Render the GRF to a canvas
|
||||
let cvs = document.createElement('canvas');
|
||||
cvs.width = w;
|
||||
cvs.height = h;
|
||||
|
||||
let ctx = cvs.getContext('2d');
|
||||
let bmap = ctx.getImageData(0, 0, w, h);
|
||||
let data = bmap.data;
|
||||
let offs = 0;
|
||||
for (let i = 0; i < l; i++) {
|
||||
let byte = bytes[i];
|
||||
for (let bit = 0x80; bit; bit = bit >>> 1, offs += 4) {
|
||||
if (bit & byte) {
|
||||
data[offs] = 0;
|
||||
data[offs+1] = 0;
|
||||
data[offs+2] = 0;
|
||||
data[offs+3] = 255; // Fully opaque
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.putImageData(bmap, 0, 0);
|
||||
return cvs;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="title">Image to ZPL</div>
|
||||
<div>
|
||||
<div style="display:inline-block">
|
||||
<div id="drop">Drop image here</div>
|
||||
</div>
|
||||
<table style="display:inline-table" borders=0 class="fields">
|
||||
<tr><th>Image Rotation<td colspan=2>
|
||||
<label for="rotN"><input type="radio" name="rot" value="N"
|
||||
id="rotN" checked>Normal</label>
|
||||
<label for="rotR"><input type="radio" name="rot" value="R"
|
||||
id="rotR">Right (CW)</label>
|
||||
<label for="rotL"><input type="radio" name="rot" value="L"
|
||||
id="rotL">Left (CCW)</label>
|
||||
<label for="rotI"><input type="radio" name="rot" value="I"
|
||||
id="rotI">Inverted</label>
|
||||
<td colspan=2 style="position:relative;padding-left:10mm">
|
||||
<button id="copyzpl" style="visibility:hidden"></button>
|
||||
<tr><th>Black Threshold
|
||||
<td><input type="number" id="black" min="1" max="99" step="1" value="50">
|
||||
<span>1..99</span>
|
||||
<td><label for="notrim">
|
||||
<input type="checkbox" id="notrim" value="Y"> No Trim</label>
|
||||
<tr><th>ZPL Format<td colspan=2>
|
||||
<label for="z64comp"><input type="radio" name="compress" value="Z64"
|
||||
id="z64comp" checked>Z64</label>
|
||||
<label for="acscomp"><input type="radio" name="compress" value="ACS"
|
||||
id="acscomp">ACS</label>
|
||||
</table>
|
||||
</div>
|
||||
<textarea rows=24 cols=112 id="zpltext" readonly></textarea>
|
||||
|
||||
<div style="display:inline-block">
|
||||
<div class="label" style="visibility:hidden">Original Image:</div>
|
||||
<div class="content" style="visibility:hidden"><img id="image"></div>
|
||||
</div>
|
||||
<div style="display:inline-block">
|
||||
<div class="label" style="visibility:hidden">Rendered Image:</div>
|
||||
<div class="content" style="visibility:hidden">
|
||||
<canvas id="canvas" width=10 height=10></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user