diff --git a/html/index.html b/html/index.html
index 44efe5c..45d3052 100644
--- a/html/index.html
+++ b/html/index.html
@@ -25,6 +25,7 @@
+
@@ -60,10 +61,14 @@
-
@@ -96,6 +101,7 @@
diff --git a/html/js/dithering.js b/html/js/dithering.js
index 9f5d78b..78407d7 100644
--- a/html/js/dithering.js
+++ b/html/js/dithering.js
@@ -1,9 +1,22 @@
-const bwrPalette = [
- [0, 0, 0, 255],
- [255, 255, 255, 255],
- [255, 0, 0, 255]
+const bwPalette = [
+ [0, 0, 0, 255], // black
+ [255, 255, 255, 255] // white
]
+const bwrPalette = [
+ [0, 0, 0, 255], // black
+ [255, 255, 255, 255], // white
+ [255, 0, 0, 255] // red
+]
+
+const bwryPalette = [
+ [0, 0, 0, 255], // black
+ [255, 255, 255, 255], // white
+ [255, 255, 0, 255], // yellow
+ [255, 0, 0, 255] // red
+]
+
+// black-white dithering
function dithering(ctx, width, height, threshold, type) {
const bayerThresholdMap = [
[ 15, 135, 45, 165 ],
@@ -43,7 +56,6 @@ function dithering(ctx, width, height, threshold, type) {
newPixel = imageData.data[currentPixel] < threshold ? 0 : 255;
err = Math.floor((imageData.data[currentPixel] - newPixel) / 16);
imageData.data[currentPixel] = newPixel;
-
imageData.data[currentPixel + 4 ] += err*7;
imageData.data[currentPixel + 4*w - 4 ] += err*3;
imageData.data[currentPixel + 4*w ] += err*5;
@@ -52,7 +64,6 @@ function dithering(ctx, width, height, threshold, type) {
newPixel = imageData.data[currentPixel] < threshold ? 0 : 255;
err = Math.floor((imageData.data[currentPixel] - newPixel) / 8);
imageData.data[currentPixel] = newPixel;
-
imageData.data[currentPixel + 4 ] += err;
imageData.data[currentPixel + 8 ] += err;
imageData.data[currentPixel + 4*w - 4 ] += err;
@@ -68,7 +79,6 @@ function dithering(ctx, width, height, threshold, type) {
ctx.putImageData(imageData, 0, 0);
}
-// white: 1, black/red: 0
function canvas2bytes(canvas, step = 'bw', invert = false) {
const ctx = canvas.getContext("2d");
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
@@ -79,25 +89,37 @@ function canvas2bytes(canvas, step = 'bw', invert = false) {
for (let y = 0; y < canvas.height; y++) {
for (let x = 0; x < canvas.width; x++) {
const i = (canvas.width * y + x) * 4;
- if (step === 'bw') {
- buffer.push(imageData.data[i] === 0 && imageData.data[i+1] === 0 && imageData.data[i+2] === 0 ? 0 : 1);
- } else {
- buffer.push(imageData.data[i] > 0 && imageData.data[i+1] === 0 && imageData.data[i+2] === 0 ? 0 : 1);
- }
- if (buffer.length === 8) {
- const data = parseInt(buffer.join(''), 2);
- arr.push(invert ? ~data : data);
- buffer = [];
+ const r = imageData.data[i];
+ const g = imageData.data[i + 1];
+ const b = imageData.data[i + 2];
+
+ if (step === 'bwry') { // black: 0, white: 1, yellow: 2, red: 3
+ buffer.push(getNearColorIdx([r, g, b, 255], bwryPalette));
+ if (buffer.length === 4) {
+ const byte = (buffer[0] << 6) | (buffer[1] << 4) | (buffer[2] << 2) | buffer[3];
+ arr.push(invert ? ~byte & 0xFF : byte);
+ buffer = [];
+ }
+ } else { // white: 1, black/red: 0
+ if (step === 'bw') {
+ buffer.push(r === 0 && g === 0 && b === 0 ? 0 : 1);
+ } else if (step === 'red') {
+ buffer.push(r > 0 && g === 0 && b === 0 ? 0 : 1);
+ }
+ if (buffer.length === 8) {
+ const data = parseInt(buffer.join(''), 2);
+ arr.push(invert ? ~data : data);
+ buffer = [];
+ }
}
}
}
return arr;
}
-function getNearColorV2(color, palette) {
+function getNearColorIdx(color, palette) {
let minDistanceSquared = 255*255 + 255*255 + 255*255 + 1;
-
let bestIndex = 0;
for (let i = 0; i < palette.length; i++) {
let rdiff = (color[0] & 0xff) - (palette[i][0] & 0xff);
@@ -109,7 +131,7 @@ function getNearColorV2(color, palette) {
bestIndex = i;
}
}
- return palette[bestIndex];
+ return bestIndex;
}
function updatePixel(imageData, index, color) {
@@ -133,27 +155,32 @@ function updatePixelErr(imageData, index, err, rate) {
imageData[index+2] += err[2] * rate;
}
-function ditheringCanvasByPalette(canvas, palette, type) {
- palette = palette || bwrPalette;
-
+// Dithering by palette
+function ditheringByPalette(canvas, type) {
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const w = imageData.width;
+ let palette = bwPalette;
+
+ if (type.startsWith("bwry")) {
+ palette = bwryPalette;
+ } else if (type.startsWith("bwr")) {
+ palette = bwrPalette;
+ }
for (let currentPixel = 0; currentPixel <= imageData.data.length; currentPixel+=4) {
- const newColor = getNearColorV2(imageData.data.slice(currentPixel, currentPixel+4), palette);
-
- if (type === "bwr_floydsteinberg") {
- const err = getColorErr(imageData.data.slice(currentPixel, currentPixel+4), newColor, 16);
+ const color = imageData.data.slice(currentPixel, currentPixel+4);
+ const newColor = palette[getNearColorIdx(color, palette)];
+ if (type.endsWith("floydsteinberg")) {
+ const err = getColorErr(color, newColor, 16);
updatePixel(imageData.data, currentPixel, newColor);
updatePixelErr(imageData.data, currentPixel +4, err, 7);
updatePixelErr(imageData.data, currentPixel + 4*w - 4, err, 3);
updatePixelErr(imageData.data, currentPixel + 4*w, err, 5);
updatePixelErr(imageData.data, currentPixel + 4*w + 4, err, 1);
} else {
- const err = getColorErr(imageData.data.slice(currentPixel, currentPixel+4), newColor, 8);
-
+ const err = getColorErr(color, newColor, 8);
updatePixel(imageData.data, currentPixel, newColor);
updatePixelErr(imageData.data, currentPixel +4, err, 1);
updatePixelErr(imageData.data, currentPixel +8, err, 1);
diff --git a/html/js/main.js b/html/js/main.js
index 251f37b..b542556 100644
--- a/html/js/main.js
+++ b/html/js/main.js
@@ -107,7 +107,7 @@ async function epdWriteImage(step = 'bw') {
for (let i = 0; i < data.length; i += chunkSize) {
let currentTime = (new Date().getTime() - startTime) / 1000.0;
- setStatus(`${step == 'bw' ? '黑白' : '红色'}块: ${chunkIdx+1}/${count+1}, 总用时: ${currentTime}s`);
+ setStatus(`${step == 'bw' ? '黑白' : '颜色'}块: ${chunkIdx+1}/${count+1}, 总用时: ${currentTime}s`);
const payload = [
(step == 'bw' ? 0x0F : 0x00) | ( i == 0 ? 0x00 : 0xF0),
...data.slice(i, i + chunkSize),
@@ -169,15 +169,22 @@ async function sendimg() {
updateButtonStatus(true);
if (appVersion < 0x16) {
- if (mode.startsWith('bwr')) {
+ if (mode.startsWith('bwry')) {
+ addLog("当前固件版本不支持四色屏幕。");
+ return;
+ } if (mode.startsWith('bwr')) {
await epdWrite(driver === "02" ? 0x24 : 0x10, canvas2bytes(canvas, 'bw'));
await epdWrite(driver === "02" ? 0x26 : 0x13, canvas2bytes(canvas, 'red', driver === '02'));
} else {
await epdWrite(driver === "04" ? 0x24 : 0x13, canvas2bytes(canvas, 'bw'));
}
} else {
- await epdWriteImage('bw');
- if (mode.startsWith('bwr')) await epdWriteImage('red');
+ if (mode.startsWith('bwry')) {
+ await epdWriteImage('bwry');
+ } else {
+ await epdWriteImage('bw');
+ if (mode.startsWith('bwr')) await epdWriteImage('red');
+ }
}
await write(EpdCmd.REFRESH);
@@ -381,7 +388,7 @@ function convertDithering() {
if (mode === '') return;
if (mode.startsWith('bwr')) {
- ditheringCanvasByPalette(canvas, bwrPalette, mode);
+ ditheringByPalette(canvas, mode);
} else {
const threshold = document.getElementById('threshold').value;
dithering(ctx, canvas.width, canvas.height, parseInt(threshold), mode);
diff --git a/html/js/paint.js b/html/js/paint.js
index 04d164e..a30ddf5 100644
--- a/html/js/paint.js
+++ b/html/js/paint.js
@@ -121,6 +121,11 @@ function updateBrushOptions() {
option.removeAttribute('disabled');
else
option.setAttribute('disabled', 'disabled');
+ } else if (option.value === '#FFFF00') {
+ if (dithering.startsWith('bwry'))
+ option.removeAttribute('disabled');
+ else
+ option.setAttribute('disabled', 'disabled');
}
}
// Revert brush color to black if red is not allowed