This commit is contained in:
Eden Kirin
2023-07-31 11:44:21 +02:00
commit 69f8ca2d6f
11 changed files with 7659 additions and 0 deletions

View 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">&nbsp;No&nbsp;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>