mirror of
https://github.com/NaitLee/Cat-Printer.git
synced 2025-05-15 23:00:15 -07:00
Layout fix; better dithering; misc corrections
This commit is contained in:
parent
db54d6004d
commit
002072b586
@ -103,13 +103,13 @@ For all supported platforms,
|
|||||||
You can also use "pure" edition once you have [Python 3](https://www.python.org/) installed,
|
You can also use "pure" edition once you have [Python 3](https://www.python.org/) installed,
|
||||||
or "bare" edition if you also managed to install `bleak` via `pip`.
|
or "bare" edition if you also managed to install `bleak` via `pip`.
|
||||||
|
|
||||||
If you like command-line, install [ImageMagick](https://imagemagick.org/) and [Ghostscript](https://ghostscript.com/) and enjoy the integraton.
|
If you like command-line, installing [ImageMagick](https://imagemagick.org/) and [Ghostscript](https://ghostscript.com/) could be very helpful.
|
||||||
|
|
||||||
See the [releases](https://github.com/NaitLee/Cat-Printer/releases) now!
|
See the [releases](https://github.com/NaitLee/Cat-Printer/releases) now!
|
||||||
|
|
||||||
## Problems?
|
## Problems?
|
||||||
|
|
||||||
Please talk in Discussion if there's something in your mind!
|
Please use Issue or Discussion if there's something in your mind!
|
||||||
|
|
||||||
Of course Pull Requests are welcome if you can handle them!
|
Of course Pull Requests are welcome if you can handle them!
|
||||||
|
|
||||||
|
15
printer.py
15
printer.py
@ -264,7 +264,7 @@ class PrinterDriver(Commander):
|
|||||||
model: Model = None
|
model: Model = None
|
||||||
'The printer model'
|
'The printer model'
|
||||||
|
|
||||||
scan_timeout: float = 5.0
|
scan_timeout: float = 4.0
|
||||||
|
|
||||||
connection_timeout : float = 5.0
|
connection_timeout : float = 5.0
|
||||||
|
|
||||||
@ -523,7 +523,7 @@ class PrinterDriver(Commander):
|
|||||||
self.device.stop_notify(self.rx_characteristic),
|
self.device.stop_notify(self.rx_characteristic),
|
||||||
self.device.disconnect()
|
self.device.disconnect()
|
||||||
)
|
)
|
||||||
except BleakError:
|
except (BleakError, EOFError):
|
||||||
self.device = None
|
self.device = None
|
||||||
if self._traffic_dump is not None:
|
if self._traffic_dump is not None:
|
||||||
self._traffic_dump.close()
|
self._traffic_dump.close()
|
||||||
@ -694,14 +694,19 @@ def main():
|
|||||||
'Run the `_main` routine while catching exceptions'
|
'Run the `_main` routine while catching exceptions'
|
||||||
try:
|
try:
|
||||||
_main()
|
_main()
|
||||||
except BleakError as e:
|
except (BleakError, AttributeError) as e:
|
||||||
error_message = str(e)
|
error_message = str(e)
|
||||||
if (
|
if (
|
||||||
'not turned on' in error_message or
|
('not turned on' in error_message) or # windows or android
|
||||||
(isinstance(e, BleakDBusError) and
|
(isinstance(e, BleakDBusError) and # linux/dbus/bluetoothctl
|
||||||
getattr(e, 'dbus_error') == 'org.bluez.Error.NotReady')
|
getattr(e, 'dbus_error') == 'org.bluez.Error.NotReady')
|
||||||
):
|
):
|
||||||
fatal(I18n['please-enable-bluetooth'], code=ExitCodes.GeneralError)
|
fatal(I18n['please-enable-bluetooth'], code=ExitCodes.GeneralError)
|
||||||
|
elif (
|
||||||
|
(isinstance(e, AttributeError) and # macos, possibly?
|
||||||
|
'CentralManagerDelegate' in error_message)
|
||||||
|
):
|
||||||
|
fatal(I18n['please-enable-bluetooth-or-try-to-reboot'], code=ExitCodes.GeneralError)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
except PrinterError as e:
|
except PrinterError as e:
|
||||||
|
@ -105,7 +105,7 @@ python3 server.py
|
|||||||
|
|
||||||
## 有问题?
|
## 有问题?
|
||||||
|
|
||||||
有想法?去 Discussion 讨论!
|
有想法?用 Issue 或去 Discussion 讨论!
|
||||||
|
|
||||||
如果能行,Pull Request 也可以!
|
如果能行,Pull Request 也可以!
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class PrinterServerHandler(BaseHTTPRequestHandler):
|
|||||||
'version': 2,
|
'version': 2,
|
||||||
'first_run': True,
|
'first_run': True,
|
||||||
'is_android': False,
|
'is_android': False,
|
||||||
'scan_timeout': 5.0,
|
'scan_timeout': 4.0,
|
||||||
'dry_run': False
|
'dry_run': False
|
||||||
})
|
})
|
||||||
_settings_blacklist = (
|
_settings_blacklist = (
|
||||||
|
32
www/image.js
32
www/image.js
@ -8,9 +8,10 @@
|
|||||||
* The result data will be here, as a 8-bit grayscale image data.
|
* The result data will be here, as a 8-bit grayscale image data.
|
||||||
* @param {number} w width of image
|
* @param {number} w width of image
|
||||||
* @param {number} h height of image
|
* @param {number} h height of image
|
||||||
|
* @param {number} t brightness, historically "threshold"
|
||||||
* @param {boolean} transparencyAsWhite whether render opacity as white rather than black
|
* @param {boolean} transparencyAsWhite whether render opacity as white rather than black
|
||||||
*/
|
*/
|
||||||
function monoGrayscale(image_data, mono_data, w, h, transparencyAsWhite) {
|
function monoGrayscale(image_data, mono_data, w, h, t, transparencyAsWhite) {
|
||||||
let p, q, r, g, b, a, m;
|
let p, q, r, g, b, a, m;
|
||||||
for (let j = 0; j < h; j++) {
|
for (let j = 0; j < h; j++) {
|
||||||
for (let i = 0; i < w; i++) {
|
for (let i = 0; i < w; i++) {
|
||||||
@ -26,6 +27,7 @@ function monoGrayscale(image_data, mono_data, w, h, transparencyAsWhite) {
|
|||||||
}
|
}
|
||||||
else { r *= a; g *= a; b *= a; }
|
else { r *= a; g *= a; b *= a; }
|
||||||
m = Math.floor(r * 0.2125 + g * 0.7154 + b * 0.0721);
|
m = Math.floor(r * 0.2125 + g * 0.7154 + b * 0.0721);
|
||||||
|
m += (t - 128) * (1 - m / 255) * (m / 255) * 2;
|
||||||
mono_data[p] = m;
|
mono_data[p] = m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,14 +38,13 @@ function monoGrayscale(image_data, mono_data, w, h, transparencyAsWhite) {
|
|||||||
* @param {Uint8ClampedArray} data the grayscale data, mentioned in `monoGrayscale`. **will be modified in-place**
|
* @param {Uint8ClampedArray} data the grayscale data, mentioned in `monoGrayscale`. **will be modified in-place**
|
||||||
* @param {number} w width of image
|
* @param {number} w width of image
|
||||||
* @param {number} h height of image
|
* @param {number} h height of image
|
||||||
* @param {number} t threshold
|
|
||||||
*/
|
*/
|
||||||
function monoDirect(data, w, h, t) {
|
function monoDirect(data, w, h) {
|
||||||
let p;
|
let p, i, j;
|
||||||
for (let j = 0; j < h; j++) {
|
for (j = 0; j < h; j++) {
|
||||||
for (let i = 0; i < w; i++) {
|
for (i = 0; i < w; i++) {
|
||||||
p = j * w + i;
|
p = j * w + i;
|
||||||
data[p] = data[p] > t ? 255 : 0;
|
data[p] = data[p] > 128 ? 255 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,10 +54,9 @@ function monoDirect(data, w, h, t) {
|
|||||||
* @param {Uint8ClampedArray} data the grayscale data, mentioned in `monoGrayscale`. **will be modified in-place**
|
* @param {Uint8ClampedArray} data the grayscale data, mentioned in `monoGrayscale`. **will be modified in-place**
|
||||||
* @param {number} w width of image
|
* @param {number} w width of image
|
||||||
* @param {number} h height of image
|
* @param {number} h height of image
|
||||||
* @param {number} t threshold
|
|
||||||
*/
|
*/
|
||||||
function monoSteinberg(data, w, h, t) {
|
function monoSteinberg(data, w, h) {
|
||||||
let p, m, n, o;
|
let p, m, n, o, i, j;
|
||||||
function adjust(x, y, delta) {
|
function adjust(x, y, delta) {
|
||||||
if (
|
if (
|
||||||
x < 0 || x >= w ||
|
x < 0 || x >= w ||
|
||||||
@ -65,12 +65,12 @@ function monoSteinberg(data, w, h, t) {
|
|||||||
p = y * w + x;
|
p = y * w + x;
|
||||||
data[p] += delta;
|
data[p] += delta;
|
||||||
}
|
}
|
||||||
for (let j = 0; j < h; j++) {
|
for (j = 0; j < h; j++) {
|
||||||
for (let i = 0; i < w; i++) {
|
for (i = 0; i < w; i++) {
|
||||||
p = j * w + i;
|
p = j * w + i;
|
||||||
m = data[p];
|
m = data[p];
|
||||||
n = m > 128 ? 255 : 0;
|
n = m > 128 ? 255 : 0;
|
||||||
o = m - n + t;
|
o = m - n;
|
||||||
data[p] = n;
|
data[p] = n;
|
||||||
adjust(i + 1, j , o * 7 / 16);
|
adjust(i + 1, j , o * 7 / 16);
|
||||||
adjust(i - 1, j + 1, o * 3 / 16);
|
adjust(i - 1, j + 1, o * 3 / 16);
|
||||||
@ -95,12 +95,12 @@ function monoHalftone(data, w, h, t) {}
|
|||||||
*/
|
*/
|
||||||
function mono2pbm(data, w, h) {
|
function mono2pbm(data, w, h) {
|
||||||
let result = new Uint8ClampedArray(data.length / 8);
|
let result = new Uint8ClampedArray(data.length / 8);
|
||||||
let slice, p;
|
let slice, p, i;
|
||||||
for (let i = 0; i < result.length; i++) {
|
for (i = 0; i < result.length; i++) {
|
||||||
p = i * 8;
|
p = i * 8;
|
||||||
slice = data.slice(p, p + 8);
|
slice = data.slice(p, p + 8);
|
||||||
// Merge 8 bytes to 1 byte, and negate the bits
|
// Merge 8 bytes to 1 byte, and negate the bits
|
||||||
// expecting in the data there's only 255 (0b11111111) or 0 (0b00000000)
|
// assuming there's only 255 (0b11111111) or 0 (0b00000000) in the data
|
||||||
result[i] = (
|
result[i] = (
|
||||||
slice[0] & 0b10000000 |
|
slice[0] & 0b10000000 |
|
||||||
slice[1] & 0b01000000 |
|
slice[1] & 0b01000000 |
|
||||||
|
@ -44,8 +44,9 @@
|
|||||||
<input type="radio" name="algo" value="algo-halftone" data-key />
|
<input type="radio" name="algo" value="algo-halftone" data-key />
|
||||||
<span data-i18n="pattern">Pattern</span>
|
<span data-i18n="pattern">Pattern</span>
|
||||||
</label> --><br />
|
</label> --><br />
|
||||||
<label for="threshold" data-i18n="threshold-">Threshold:</label>
|
<!-- "brightness" is historically "threshold" -->
|
||||||
<input type="range" min="0" max="256" value="128" step="8" id="threshold" data-key data-default />
|
<label for="threshold" data-i18n="brightness-">Brightness:</label>
|
||||||
|
<input type="range" min="0" max="256" value="86" step="1" id="threshold" data-key data-default />
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="transparent-as-white" id="transparent-as-white" data-key checked />
|
<input type="checkbox" name="transparent-as-white" id="transparent-as-white" data-key checked />
|
||||||
<label for="transparent-as-white" data-i18n="transparent-as-white">Transparent as White</label>
|
<label for="transparent-as-white" data-i18n="transparent-as-white">Transparent as White</label>
|
||||||
@ -62,7 +63,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel" id="panel-settings">
|
<div class="panel" id="panel-settings">
|
||||||
<label for="scan-time" data-i18n="scan-time-">Scan Time:</label>
|
<label for="scan-time" data-i18n="scan-time-">Scan Time:</label>
|
||||||
<input type="number" name="scan-time" id="scan-time" min="1" max="10" value="3" data-key />
|
<input type="number" name="scan-time" id="scan-time" min="1" max="10" value="4" data-key />
|
||||||
<span data-i18n="-seconds">seconds</span>
|
<span data-i18n="-seconds">seconds</span>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="flip-h" id="flip-h" data-key />
|
<input type="checkbox" name="flip-h" id="flip-h" data-key />
|
||||||
|
@ -116,5 +116,8 @@
|
|||||||
"text-printing-mode-with-options": "Text printing mode with options",
|
"text-printing-mode-with-options": "Text printing mode with options",
|
||||||
"image-printing-options": "Image printing options",
|
"image-printing-options": "Image printing options",
|
||||||
"convert-input-image-with-imagemagick": "Convert input image with ImageMagick",
|
"convert-input-image-with-imagemagick": "Convert input image with ImageMagick",
|
||||||
"reset-configuration-": "Reset configuration?"
|
"reset-configuration-": "Reset configuration?",
|
||||||
|
"brightness-": "Brightness:",
|
||||||
|
"text-printing-mode": "Text Printing Mode",
|
||||||
|
"please-enable-bluetooth-or-try-to-reboot": "Please enable bluetooth or try to reboot"
|
||||||
}
|
}
|
@ -111,5 +111,8 @@
|
|||||||
"text-printing-mode-with-options": "启用文字打印并指定选项",
|
"text-printing-mode-with-options": "启用文字打印并指定选项",
|
||||||
"image-printing-options": "图片打印选项",
|
"image-printing-options": "图片打印选项",
|
||||||
"convert-input-image-with-imagemagick": "使用 ImageMagick 转换输入图片",
|
"convert-input-image-with-imagemagick": "使用 ImageMagick 转换输入图片",
|
||||||
"reset-configuration-": "要重置配置吗?"
|
"reset-configuration-": "要重置配置吗?",
|
||||||
|
"brightness-": "亮度:",
|
||||||
|
"text-printing-mode": "文字打印模式",
|
||||||
|
"please-enable-bluetooth-or-try-to-reboot": "请启用蓝牙或尝试重启"
|
||||||
}
|
}
|
40
www/main.css
40
www/main.css
@ -1,8 +1,10 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--font-size: 1.2rem;
|
--font-size: 1.2rem;
|
||||||
|
/* --dpi-zoom: 0.96; */
|
||||||
--deco-size: calc(var(--font-size) / 2);
|
--deco-size: calc(var(--font-size) / 2);
|
||||||
--line-height: 1.8em;
|
--line-height: calc(var(--font-size) / 2 * 3);
|
||||||
|
--compact-menu-height: 2em;
|
||||||
--span: 8px;
|
--span: 8px;
|
||||||
--span-half: calc(var(--span) / 2);
|
--span-half: calc(var(--span) / 2);
|
||||||
--span-double: calc(var(--span) * 2);
|
--span-double: calc(var(--span) * 2);
|
||||||
@ -94,6 +96,7 @@ button:active {
|
|||||||
}
|
}
|
||||||
#notice {
|
#notice {
|
||||||
min-height: var(--font-size);
|
min-height: var(--font-size);
|
||||||
|
margin: var(--span-half) 0;
|
||||||
}
|
}
|
||||||
#notice span {
|
#notice span {
|
||||||
display: block;
|
display: block;
|
||||||
@ -159,9 +162,9 @@ main>.menu-side>.menu {
|
|||||||
}
|
}
|
||||||
.compact-button {
|
.compact-button {
|
||||||
width: max-content;
|
width: max-content;
|
||||||
height: 2em;
|
height: var(--compact-menu-height);
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
line-height: 2em;
|
line-height: var(--compact-menu-height);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
@ -171,8 +174,9 @@ main>.menu-side>.menu {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.compact-button:hover {
|
.compact-button:hover {
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0 var(--span) calc(var(--span-double));
|
||||||
|
min-width: 6em;
|
||||||
}
|
}
|
||||||
.compact-button.active {
|
.compact-button.active {
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
@ -221,8 +225,9 @@ p {
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
.panel.active {
|
.panel.active {
|
||||||
height: var(--panel-height);
|
height: calc(var(--panel-height) - var(--compact-menu-height));
|
||||||
padding: var(--span-double) var(--span);
|
padding: var(--span-double) var(--span);
|
||||||
|
box-sizing: border-box;
|
||||||
/* overflow-y: scroll; */
|
/* overflow-y: scroll; */
|
||||||
}
|
}
|
||||||
.panel.sub.active {
|
.panel.sub.active {
|
||||||
@ -451,7 +456,13 @@ a {
|
|||||||
from { overflow: hidden; }
|
from { overflow: hidden; }
|
||||||
to { overflow: auto; }
|
to { overflow: auto; }
|
||||||
}
|
}
|
||||||
@media (max-width: 800px) {
|
|
||||||
|
@media (max-height: 520px) {
|
||||||
|
body, main { margin: 0 auto; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.5px) {
|
||||||
|
/* My test shows it's Just 768 fit best */
|
||||||
:root {
|
:root {
|
||||||
--panel-height: 16em;
|
--panel-height: 16em;
|
||||||
--font-size: 1em;
|
--font-size: 1em;
|
||||||
@ -466,14 +477,14 @@ a {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: var(--line-height);
|
top: calc(var(--line-height) + var(--span));
|
||||||
height: calc(100% - var(--panel-height) - 2em);
|
height: calc(100% - var(--panel-height) - var(--compact-menu-height));
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
main>.canvas-side>.buttons,
|
main>.canvas-side>.buttons,
|
||||||
main>.menu-side>.buttons {
|
main>.menu-side>.buttons {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 2em;
|
bottom: var(--compact-menu-height);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
@ -495,7 +506,7 @@ a {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
main>.menu-side>.menu {
|
main>.menu-side>.menu {
|
||||||
height: var(--panel-height);
|
height: calc(var(--panel-height) - var(--compact-menu-height));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
#notice {
|
#notice {
|
||||||
@ -510,7 +521,7 @@ a {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
.blank {
|
.blank {
|
||||||
height: 2em;
|
height: var(--compact-menu-height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: 384px) {
|
@media (max-width: 384px) {
|
||||||
@ -520,6 +531,13 @@ a {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @media (min-resolution: 120dpi) {
|
||||||
|
:root { --font-size: calc(1.2rem * var(--dpi-zoom)); }
|
||||||
|
}
|
||||||
|
@media (min-resolution: 144dpi) {
|
||||||
|
:root { --font-size: calc(1.2rem * var(--dpi-zoom) * var(--dpi-zoom)); }
|
||||||
|
} */
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root { --fore-color: #eee; --back-color: #333; --shade: rgba(51, 51, 51, 0.5); }
|
:root { --fore-color: #eee; --back-color: #333; --shade: rgba(51, 51, 51, 0.5); }
|
||||||
body, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
body, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
||||||
|
26
www/main.js
26
www/main.js
@ -4,7 +4,7 @@
|
|||||||
/**
|
/**
|
||||||
* In order to debug on a phone, we load vConsole
|
* In order to debug on a phone, we load vConsole
|
||||||
* https://www.npmjs.com/package/vconsole
|
* https://www.npmjs.com/package/vconsole
|
||||||
* Double-tap the "Cat Printer" title to activate
|
* Double-tap notice bar to activate
|
||||||
*/
|
*/
|
||||||
function debug() {
|
function debug() {
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
@ -12,7 +12,7 @@ function debug() {
|
|||||||
document.body.appendChild(script);
|
document.body.appendChild(script);
|
||||||
script.addEventListener('load', () => new window.VConsole());
|
script.addEventListener('load', () => new window.VConsole());
|
||||||
}
|
}
|
||||||
document.getElementById('title').addEventListener('dblclick', debug);
|
document.getElementById('notice').addEventListener('dblclick', debug);
|
||||||
|
|
||||||
var hidden_area = document.getElementById('hidden');
|
var hidden_area = document.getElementById('hidden');
|
||||||
|
|
||||||
@ -243,6 +243,10 @@ function putEvent(selector, type, callback, thisArg) {
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to control Printing Canvas (manipulate, preview etc.)
|
||||||
|
* "Brightness" is historically "Threshold", while the later is kept in code
|
||||||
|
*/
|
||||||
class CanvasController {
|
class CanvasController {
|
||||||
/** @type {HTMLCanvasElement} */
|
/** @type {HTMLCanvasElement} */
|
||||||
preview;
|
preview;
|
||||||
@ -252,11 +256,18 @@ class CanvasController {
|
|||||||
imageUrl;
|
imageUrl;
|
||||||
isCanvas;
|
isCanvas;
|
||||||
algorithm;
|
algorithm;
|
||||||
threshold;
|
_threshold;
|
||||||
thresholdRange;
|
get threshold() {
|
||||||
|
return this._threshold;
|
||||||
|
}
|
||||||
|
set threshold(value) {
|
||||||
|
this._threshold = this._thresholdRange.value = value;
|
||||||
|
}
|
||||||
|
_thresholdRange;
|
||||||
transparentAsWhite;
|
transparentAsWhite;
|
||||||
previewData;
|
previewData;
|
||||||
static defaultHeight = 384;
|
static defaultHeight = 384;
|
||||||
|
static defaultThreshold = 256 / 3;
|
||||||
_height;
|
_height;
|
||||||
get height() {
|
get height() {
|
||||||
return this._height;
|
return this._height;
|
||||||
@ -269,7 +280,7 @@ class CanvasController {
|
|||||||
this.canvas = document.getElementById('control-canvas');
|
this.canvas = document.getElementById('control-canvas');
|
||||||
this.div = document.getElementById('control-document');
|
this.div = document.getElementById('control-document');
|
||||||
this.height = CanvasController.defaultHeight;
|
this.height = CanvasController.defaultHeight;
|
||||||
this.thresholdRange = document.getElementById('threshold');
|
this._thresholdRange = document.getElementById('threshold');
|
||||||
this.imageUrl = null;
|
this.imageUrl = null;
|
||||||
|
|
||||||
putEvent('input[name="mode"]', 'change', (event) => this.enableMode(event.currentTarget.value), this);
|
putEvent('input[name="mode"]', 'change', (event) => this.enableMode(event.currentTarget.value), this);
|
||||||
@ -304,7 +315,8 @@ class CanvasController {
|
|||||||
}
|
}
|
||||||
useAlgorithm(name) {
|
useAlgorithm(name) {
|
||||||
this.algorithm = name;
|
this.algorithm = name;
|
||||||
this.thresholdRange.value = 128;
|
this.threshold = CanvasController.defaultThreshold;
|
||||||
|
this._thresholdRange.dispatchEvent(new Event('change'));
|
||||||
this.activatePreview();
|
this.activatePreview();
|
||||||
}
|
}
|
||||||
expand(length = CanvasController.defaultHeight) {
|
expand(length = CanvasController.defaultHeight) {
|
||||||
@ -322,7 +334,7 @@ class CanvasController {
|
|||||||
let context_p = preview.getContext('2d');
|
let context_p = preview.getContext('2d');
|
||||||
let data = context_c.getImageData(0, 0, w, h);
|
let data = context_c.getImageData(0, 0, w, h);
|
||||||
let mono_data = new Uint8ClampedArray(w * h);
|
let mono_data = new Uint8ClampedArray(w * h);
|
||||||
monoGrayscale(data.data, mono_data, w, h, this.transparentAsWhite);
|
monoGrayscale(data.data, mono_data, w, h, t, this.transparentAsWhite);
|
||||||
switch (this.algorithm) {
|
switch (this.algorithm) {
|
||||||
case 'algo-direct':
|
case 'algo-direct':
|
||||||
monoDirect(mono_data, w, h, t);
|
monoDirect(mono_data, w, h, t);
|
||||||
|
@ -1,8 +1,29 @@
|
|||||||
|
// Polyfills
|
||||||
|
|
||||||
/**
|
// home-made minimal fetch
|
||||||
* Polyfill
|
// Note: only useful with this application. Extend (or remove) it as needed.
|
||||||
*/
|
// In fact I wanted to support Otter Browser for resource-concerning people
|
||||||
(function() {
|
// But it still can't cope with few other JS (even after transpiled to es5) and CSS variables
|
||||||
if (!NodeList.prototype.forEach)
|
if (!window.fetch) window.fetch = function(url, options) {
|
||||||
NodeList.prototype.forEach = Array.prototype.forEach;
|
options = options || {};
|
||||||
})();
|
return new Promise(function(resolve, reject) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open(options.method || 'GET', url);
|
||||||
|
function response(is_binary) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
resolve(is_binary ? xhr.response : xhr.responseText);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xhr.onload = function() {
|
||||||
|
resolve({
|
||||||
|
text: function() { return response(false); },
|
||||||
|
json: function() { return response(false).then(t => JSON.parse(t)); },
|
||||||
|
ok: Math.floor(xhr.status / 100) === 2
|
||||||
|
});
|
||||||
|
}
|
||||||
|
xhr.send(options.body || null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// and this
|
||||||
|
if (!NodeList.prototype.forEach) NodeList.prototype.forEach = Array.prototype.forEach;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user