mirror of
https://github.com/NaitLee/Cat-Printer.git
synced 2025-05-16 15:20:12 -07:00
better css; image rotation; lolcat i18n; update about
the works are still incomplete. expecting more code cleaning
This commit is contained in:
parent
947cb9a5b9
commit
502a572183
1
TODO
1
TODO
@ -12,6 +12,7 @@ Note: not ordered. do whatever I/you want
|
|||||||
+ Make a build guide for android:
|
+ Make a build guide for android:
|
||||||
Summary the hacks to p4a, bleak p4a recipe, p4a webview bootstrap, and AdvancedWebView
|
Summary the hacks to p4a, bleak p4a recipe, p4a webview bootstrap, and AdvancedWebView
|
||||||
+ Try to implement enough without more dependencies
|
+ Try to implement enough without more dependencies
|
||||||
|
+ More funny i18n
|
||||||
+ Arch Linux package / AUR, package for other distros
|
+ Arch Linux package / AUR, package for other distros
|
||||||
+ Service for other init systems (a systemd unit file is there)
|
+ Service for other init systems (a systemd unit file is there)
|
||||||
+ ...
|
+ ...
|
||||||
|
@ -153,3 +153,34 @@ That may involve another (partial) rewrite.
|
|||||||
Afraid not, experiment always worth it. And remember: it's all about idea, everyone can make use of then.
|
Afraid not, experiment always worth it. And remember: it's all about idea, everyone can make use of then.
|
||||||
|
|
||||||
Yawn... bed time...
|
Yawn... bed time...
|
||||||
|
|
||||||
|
9th
|
||||||
|
|
||||||
|
Did some stylesheet fix.
|
||||||
|
|
||||||
|
Then go for image rotation. It shouldn't be that hard:
|
||||||
|
|
||||||
|
0 1 2 3 16 17 18 19 32 33 34 35 48 49 50 51
|
||||||
|
4 5 6 7 20 21 22 23 36 37 38 39 52 53 54 55
|
||||||
|
8 9 10 11 24 25 26 27 40 41 42 43 56 57 58 59
|
||||||
|
12 13 14 15 28 29 30 31 44 45 46 47 60 61 62 63
|
||||||
|
16 17 18 19 32 33 34 35 48 49 50 51 64 65 66 67
|
||||||
|
20 21 22 23 36 37 38 39 52 53 54 55 68 69 70 71
|
||||||
|
|
||||||
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
||||||
|
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
||||||
|
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
||||||
|
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
||||||
|
|
||||||
|
Think about HTML canvas ImageData, one dimensional [R,G,B,A,...] array.
|
||||||
|
The "big" problem is just make a procedure to transform from the first matrix to the second.
|
||||||
|
(and flip the result horizontally)
|
||||||
|
|
||||||
|
Know what happened? I produced a right procedure from very start, but the image screwed up.
|
||||||
|
|
||||||
|
Tried to "fix" it, used at least 4 hours, finally found it's a matter of didn't floor a floating number.
|
||||||
|
(Height is got by multiplying aspect ratio)
|
||||||
|
|
||||||
|
So the Internet JavaScript memes are damned true.
|
||||||
|
https://programmerhumor.io/javascript-memes/why-is-it-like-this-2/
|
||||||
|
https://programmerhumor.io/javascript-memes/sorry-dad-_-2/
|
||||||
|
@ -635,7 +635,7 @@ def _main():
|
|||||||
parser.add_argument('-f', '--fake', metavar='XY01', type=str, default='',
|
parser.add_argument('-f', '--fake', metavar='XY01', type=str, default='',
|
||||||
help=i18n('virtual-run-on-specified-model'))
|
help=i18n('virtual-run-on-specified-model'))
|
||||||
parser.add_argument('-m', '--dump', action='store_true',
|
parser.add_argument('-m', '--dump', action='store_true',
|
||||||
help=i18n('dump-the-traffic'))
|
help=i18n('dump-traffic'))
|
||||||
parser.add_argument('-n', '--nothing', action='store_true',
|
parser.add_argument('-n', '--nothing', action='store_true',
|
||||||
help=i18n('do-nothing'))
|
help=i18n('do-nothing'))
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<a target="_blank" href="https://github.com/NaitLee">NaitLee</a>
|
<a target="_blank" href="https://github.com/NaitLee">NaitLee</a>
|
||||||
</dt>
|
</dt>
|
||||||
<dd data-i18n="developer">Developer</dd>
|
<dd data-i18n="developer">Developer</dd>
|
||||||
|
<dd data-i18n="translator">Translator</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>
|
<dt>
|
||||||
@ -32,7 +33,19 @@
|
|||||||
<dd data-i18n="translator">Translator</dd>
|
<dd data-i18n="translator">Translator</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<dl>
|
<dl>
|
||||||
<dt data-i18n="all-testers-and-users">All testers & users</dt>
|
<dt>
|
||||||
|
<a target="_blank" href="https://github.com/andypiper">andypiper</a>
|
||||||
|
</dt>
|
||||||
|
<dd data-i18n="minor-tweaks">Minor Tweaks</dd>
|
||||||
|
</dl>
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
<a target="_blank" href="https://github.com/sync1211">sync1211</a>
|
||||||
|
</dt>
|
||||||
|
<dd data-i18n="developer">Developer</dd>
|
||||||
|
</dl>
|
||||||
|
<dl>
|
||||||
|
<dt data-i18n="all-users-and-developers">All testers & users</dt>
|
||||||
<dd data-i18n="everyone-is-awesome">Everyone is awesome!</dd>
|
<dd data-i18n="everyone-is-awesome">Everyone is awesome!</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,14 +26,14 @@
|
|||||||
<span class="label-span-input">
|
<span class="label-span-input">
|
||||||
<span data-i18n="process-as-">Process as:</span>
|
<span data-i18n="process-as-">Process as:</span>
|
||||||
<span>
|
<span>
|
||||||
<label>
|
|
||||||
<input type="radio" name="algo" value="algo-direct" data-key />
|
|
||||||
<span data-i18n="text">Text</span>
|
|
||||||
</label>
|
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="algo" value="algo-steinberg" data-key checked />
|
<input type="radio" name="algo" value="algo-steinberg" data-key checked />
|
||||||
<span data-i18n="picture">Picture</span>
|
<span data-i18n="picture">Picture</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="algo" value="algo-direct" data-key />
|
||||||
|
<span data-i18n="text">Text</span>
|
||||||
|
</label>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<!-- "brightness" is historically "threshold" -->
|
<!-- "brightness" is historically "threshold" -->
|
||||||
@ -52,6 +52,10 @@
|
|||||||
<input type="range" min="24" max="36" value="32" step="4" name="quality" data-key data-default />
|
<input type="range" min="24" max="36" value="32" step="4" name="quality" data-key data-default />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<label class="label-input-span">
|
||||||
|
<input type="checkbox" name="rotate" data-key />
|
||||||
|
<span data-i18n="rotate-image">Rotate Image</span>
|
||||||
|
</label>
|
||||||
<label class="label-input-span" data-hide-as="print">
|
<label class="label-input-span" data-hide-as="print">
|
||||||
<input type="checkbox" name="transparent-as-white" data-key checked />
|
<input type="checkbox" name="transparent-as-white" data-key checked />
|
||||||
<span data-i18n="transparent-as-white">Transparent as White</span>
|
<span data-i18n="transparent-as-white">Transparent as White</span>
|
||||||
@ -120,7 +124,7 @@
|
|||||||
<div id="control-overlay">
|
<div id="control-overlay">
|
||||||
<div>
|
<div>
|
||||||
<button id="insert-picture" data-i18n="insert-picture" data-key="Enter">Insert Picture</button>
|
<button id="insert-picture" data-i18n="insert-picture" data-key="Enter">Insert Picture</button>
|
||||||
<button id="insert-text" data-i18n="insert-text" data-key="">Insert Text</button>
|
<button id="insert-text" data-i18n="insert-text" data-key="\">Insert Text</button>
|
||||||
<p data-i18n="or-drag-file-to-below" class="hide-on-android">Or drag file to below</p>
|
<p data-i18n="or-drag-file-to-below" class="hide-on-android">Or drag file to below</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -131,7 +135,6 @@
|
|||||||
<div class="center buttons">
|
<div class="center buttons">
|
||||||
<!-- <button id="canvas-expand" data-i18n="expand">Expand</button>
|
<!-- <button id="canvas-expand" data-i18n="expand">Expand</button>
|
||||||
<button id="canvas-crop" data-i18n="crop">Crop</button> -->
|
<button id="canvas-crop" data-i18n="crop">Crop</button> -->
|
||||||
<!-- <button id="button-preview" data-i18n="preview">Preview</button> -->
|
|
||||||
<button id="button-reset" data-i18n="reset" data-key>Reset</button>
|
<button id="button-reset" data-i18n="reset" data-key>Reset</button>
|
||||||
<button id="button-print" data-i18n="print" data-key=" ">Print</button>
|
<button id="button-print" data-i18n="print" data-key=" ">Print</button>
|
||||||
</div>
|
</div>
|
||||||
@ -141,6 +144,7 @@
|
|||||||
<div id="hidden" class="hard-hidden">
|
<div id="hidden" class="hard-hidden">
|
||||||
<!-- Hidden area for putting elements -->
|
<!-- Hidden area for putting elements -->
|
||||||
<input type="file" id="file" />
|
<input type="file" id="file" />
|
||||||
|
<img src="" id="img" alt="hidden-image" />
|
||||||
<div id="accessibility">
|
<div id="accessibility">
|
||||||
<div>
|
<div>
|
||||||
<h2>
|
<h2>
|
||||||
@ -180,42 +184,37 @@
|
|||||||
<div id="text-input">
|
<div id="text-input">
|
||||||
<h1 data-i18n="insert-text">Insert Text</h1>
|
<h1 data-i18n="insert-text">Insert Text</h1>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<div id="text-settings">
|
<div id="text-settings">
|
||||||
<div name="font-and-size" class="text-settings-group">
|
<div name="font-and-size" class="text-settings-group">
|
||||||
|
<select id="text-font" contenteditable="true" data-key>
|
||||||
<select id="text-font">
|
<option value="serif" data-i18n="serif">Serif</option>
|
||||||
<option value="Arial">Arial (sans-serif)</option>
|
<option value="sans-serif" data-i18n="sans-serif" selected>Sans Serif</option>
|
||||||
<option value="Brush Script MT">Brush Script MT (cursive)</option>
|
<option value="monospace" data-i18n="monospace">Monospace</option>
|
||||||
<option value="Courier New">Courier New (monospace)</option>
|
<option value="Unifont" data-i18n="unifont">Unifont</option>
|
||||||
<option value="Garamond">Garamond (serif)</option>
|
|
||||||
<option value="Georgia">Georgia (serif)</option>
|
|
||||||
<option value="Helvetica" selected>Helvetica (sans-serif)</option>
|
|
||||||
<option value="Tahoma">Tahoma (sans-serif)</option>
|
|
||||||
<option value="Times New Roman">Times New Roman (serif)</option>
|
|
||||||
<option value="Trebuchet MS">Trebuchet MS (sans-serif)</option>
|
|
||||||
<option value="Verdana">Verdana (sans-serif)</option>
|
|
||||||
</select>
|
</select>
|
||||||
<input id="text-size" type="number" name="text-size" min="1" max="100" value="20" data-key style="margin: 0px;"/>
|
<input id="text-size" type="number" name="text-size" min="1" max="100" value="20" data-key style="margin: 0px;"/>
|
||||||
</div>
|
</div>
|
||||||
<div name="wrap-and-align" class="text-settings-group">
|
<div name="wrap-and-align" class="text-settings-group">
|
||||||
<label data-i18n="wrap-by-space" name="wrap-by-space-label"><input type="checkbox" name="wrap-by-space" data-key checked />Wrap text</label>
|
<label>
|
||||||
|
<input type="checkbox" name="wrap-words-by-spaces" data-key checked />
|
||||||
|
<span data-i18n="wrap-words-by-spaces">Wrap words by spaces</span>
|
||||||
|
</label>
|
||||||
<span class="text-align-container">
|
<span class="text-align-container">
|
||||||
<input type="radio" name="text-align" value="left" checked/>
|
<input type="radio" name="text-align" value="left" data-key checked />
|
||||||
<span class="text-align-checkmark text-align-left"></span>
|
<span class="text-align-checkmark text-align-left"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="text-align-container">
|
<span class="text-align-container">
|
||||||
<input type="radio" name="text-align" value="center"/>
|
<input type="radio" name="text-align" value="center" data-key />
|
||||||
<span class="text-align-checkmark text-align-center"></span>
|
<span class="text-align-checkmark text-align-center"></span>
|
||||||
</span>
|
</span>
|
||||||
<span class="text-align-container">
|
<span class="text-align-container">
|
||||||
<input type="radio" name="text-align" value="right"/>
|
<input type="radio" name="text-align" value="right" data-key />
|
||||||
<span class="text-align-checkmark text-align-right"></span>
|
<span class="text-align-checkmark text-align-right"></span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="text-textarea">
|
<div id="text-textarea">
|
||||||
<textarea id="insert-text-area"></textarea>
|
<textarea id="insert-text-area" data-key="/"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
"supported-models-": "Unterstützte Modelle:",
|
"supported-models-": "Unterstützte Modelle:",
|
||||||
"path-to-input-file-dash-for-stdin": "Pfad zur Datei. '-' für stdin",
|
"path-to-input-file-dash-for-stdin": "Pfad zur Datei. '-' für stdin",
|
||||||
"scan-for-specified-seconds": "Suchlauf für die angegebenen Sekunden",
|
"scan-for-specified-seconds": "Suchlauf für die angegebenen Sekunden",
|
||||||
"dump-the-traffic": "Den Datenverkehr auf dem Drucker ausgeben und PBM-Bild beim Textdruck",
|
|
||||||
"text-printing-mode": "Textdruckmodus",
|
"text-printing-mode": "Textdruckmodus",
|
||||||
"please-install-pyobjc-via-pip": "Bitte installieren Sie `pyobjc` über pip",
|
"please-install-pyobjc-via-pip": "Bitte installieren Sie `pyobjc` über pip",
|
||||||
"please-install-bleak-via-pip": "Bitte installieren Sie `bleak` über pip",
|
"please-install-bleak-via-pip": "Bitte installieren Sie `bleak` über pip",
|
||||||
@ -94,7 +93,7 @@
|
|||||||
"contributors": "Beitragende",
|
"contributors": "Beitragende",
|
||||||
"developer": "Entwickler",
|
"developer": "Entwickler",
|
||||||
"translator": "Übersetzer",
|
"translator": "Übersetzer",
|
||||||
"all-testers-and-users": "All Tester & Benutzer",
|
"all-users-and-developers": "All Tester & Benutzer",
|
||||||
"everyone-is-awesome": "Jeder ist super",
|
"everyone-is-awesome": "Jeder ist super",
|
||||||
"license": "Lizenz",
|
"license": "Lizenz",
|
||||||
"exiting": "Exiting…",
|
"exiting": "Exiting…",
|
||||||
@ -107,5 +106,5 @@
|
|||||||
"text-font": "Schriftart",
|
"text-font": "Schriftart",
|
||||||
"text-size": "Textgröße",
|
"text-size": "Textgröße",
|
||||||
"enter-text": "Text eingeben",
|
"enter-text": "Text eingeben",
|
||||||
"wrap-by-space": "Autom. Zeilenumbruch"
|
"wrap-words-by-spaces": "Autom. Zeilenumbruch"
|
||||||
}
|
}
|
@ -91,7 +91,7 @@
|
|||||||
"contributors": "Contributors",
|
"contributors": "Contributors",
|
||||||
"developer": "Developer",
|
"developer": "Developer",
|
||||||
"translator": "Translator",
|
"translator": "Translator",
|
||||||
"all-testers-and-users": "All testers & users",
|
"all-users-and-developers": "All users & developers",
|
||||||
"everyone-is-awesome": "Everyone is awesome!",
|
"everyone-is-awesome": "Everyone is awesome!",
|
||||||
"license": "License",
|
"license": "License",
|
||||||
"exiting": "Exiting…",
|
"exiting": "Exiting…",
|
||||||
@ -132,5 +132,10 @@
|
|||||||
"text-font": "Font",
|
"text-font": "Font",
|
||||||
"text-size": "Size",
|
"text-size": "Size",
|
||||||
"enter-text": "Enter text",
|
"enter-text": "Enter text",
|
||||||
"wrap-by-space": "Wrap words by spaces"
|
"wrap-words-by-spaces": "Wrap words by spaces",
|
||||||
|
"minor-tweaks": "Minor Tweaks",
|
||||||
|
"serif": "Serif",
|
||||||
|
"sans-serif": "Sans Serif",
|
||||||
|
"monospace": "Monospace",
|
||||||
|
"rotate-image": "Rotate Image"
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"en-US": "English (US)",
|
"en-US": "English (US)",
|
||||||
"zh-CN": "中文(简体)",
|
"zh-CN": "中文(简体)",
|
||||||
"de-DE": "Deutsch"
|
"de-DE": "Deutsch",
|
||||||
|
"lolcat": "LOLCAT"
|
||||||
}
|
}
|
136
www/lang/lolcat.json
Normal file
136
www/lang/lolcat.json
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
{
|
||||||
|
"$language": "LOLCAT",
|
||||||
|
"cat-printer": "KITTE PAWS 🐾",
|
||||||
|
"printer": "PAWS",
|
||||||
|
"device-": "KITTE>",
|
||||||
|
"refresh": "FIND",
|
||||||
|
"mode-": "HOW>",
|
||||||
|
"canvas": "VIEW",
|
||||||
|
"document": "DOC",
|
||||||
|
"insert-picture": "PUT CAT PIC",
|
||||||
|
"insert-text": "SAY MEOW",
|
||||||
|
"help": "HALP",
|
||||||
|
"javascript-license-information": "BROWSR JUNK",
|
||||||
|
"settings": "CONFIGUR",
|
||||||
|
"image": "PIC",
|
||||||
|
"threshold-": "BLAK OR WHITE",
|
||||||
|
"transparent-as-white": "DONT POLUT PIC",
|
||||||
|
"misc": "OTHR",
|
||||||
|
"system": "SYS",
|
||||||
|
"disable-animation": "NO MOTION",
|
||||||
|
"exit": "BAK TO HOM",
|
||||||
|
"error-message": "SOMTHIN WRONG",
|
||||||
|
"preview": "LOOK",
|
||||||
|
"print": "PAW STEP",
|
||||||
|
"expand": "MORE",
|
||||||
|
"crop": "LESS",
|
||||||
|
"scanning-for-devices": "LUKIN FOR KITTEZ",
|
||||||
|
"scan-time-": "HOW LONG TO FIND",
|
||||||
|
"-seconds": "SECS",
|
||||||
|
"no-available-devices-found": "NO KITTE FOUND",
|
||||||
|
"found-0-available-devices": {
|
||||||
|
"single": "THER IS {0} KITTE",
|
||||||
|
"multiple": "THER R {0} KITTEZ"
|
||||||
|
},
|
||||||
|
"please-check-if-the-printer-is-down": "CHEK IF KITTE IS SLIPIN",
|
||||||
|
"printing": "KITTE WALKIN…",
|
||||||
|
"finished": "K BYE!!",
|
||||||
|
"coming-soon": "COMIN SOON…",
|
||||||
|
"dry-run": "DONT STEP WITH INK",
|
||||||
|
"dry-run-test-print-process-only": "WONT REILLY STEP NOW",
|
||||||
|
"you-can-close-this-page-manually": "KITTE SLEP YA MAY GO",
|
||||||
|
"please-enable-bluetooth": "OPEN YA BLUETOOTH PLZ",
|
||||||
|
"error-happened-please-check-error-message": "SOMTHIN WRONG CHK ERR LOG PLZ",
|
||||||
|
"you-can-seek-for-help-with-detailed-info-below": "ASK OTHR KITTE WITH THEZ",
|
||||||
|
"or-try-to-scan-longer": "TRY TO FIND BIT LONGER",
|
||||||
|
"print-to-cat-printer": "PAWS TO STEP ON PAPR OF KITTE PRINTER!",
|
||||||
|
"supported-models-": "KNOWN KITTEZ>",
|
||||||
|
"path-to-input-file-dash-for-stdin": "WHAT FILE TO STEP '-' MEAN STDIN",
|
||||||
|
"please-install-pyobjc-via-pip": "INSTAL `pyobjc` VIA pip",
|
||||||
|
"please-install-bleak-via-pip": "INSTAL `bleak` VIA pip",
|
||||||
|
"folder-printer_lib-is-incomplete-or-missing-please-check": "DIR `printer_lib` HAV PROBLM CHK PLZ",
|
||||||
|
"input-is-not-pbm-image": "INPUT ISNT PBM PIC",
|
||||||
|
"unsuitable-image-width-expected-0-got-1": "WRONG PIC WIDZ {0} WANT {1}",
|
||||||
|
"broken-pbm-image": "BAD PBM PIC",
|
||||||
|
"input-is-not-text-file": "SAY MEOW MEOW NOT PIC",
|
||||||
|
"match-printer-with-this-name-or-address": "PICK TIS KITTE NAM,ADDR",
|
||||||
|
"virtual-run-on-specified-model": "DREAM ABOUT TIS KITTE YA DONT HAVE",
|
||||||
|
"font-size-0": "PAW BIG AS {0}",
|
||||||
|
"stopping": "LEAVIN",
|
||||||
|
"connecting": "IM COMIN",
|
||||||
|
"model-0-is-not-supported-yet": "KITTE '{0}' UNKNON",
|
||||||
|
"invalid-address-0": "THER ISNT A KITTE AT '{0}'",
|
||||||
|
"will-listen-on-all-addresses": "GATHER CONN ON ALL ADDRS",
|
||||||
|
"serving-at-0": "IM AT {0}",
|
||||||
|
"disconnecting-from-printer": "LEAVIN KITTE",
|
||||||
|
"connected-to-0-1": "PICKD TIS {0} {1}",
|
||||||
|
"flip-horizontally": "FLIP <>",
|
||||||
|
"flip-vertically": "FLIP ^v",
|
||||||
|
"dump-traffic": "WACH KITTE PAWS",
|
||||||
|
"right-to-left-text-order": "YA READ RTL",
|
||||||
|
"auto-wrap-line": "WRAP MEOW",
|
||||||
|
"process-as-": "HOW TO STEP>",
|
||||||
|
"text": "MEOW",
|
||||||
|
"picture": "PICS",
|
||||||
|
"pattern": "SPOTS",
|
||||||
|
"large-font": "BIGGR PAW",
|
||||||
|
"accessibility": "IM SPECIAL",
|
||||||
|
"language": "WHAT YA SAY",
|
||||||
|
"layout": "WHAT YA LOOK",
|
||||||
|
"ok": "GO",
|
||||||
|
"cancel": "BACK",
|
||||||
|
"yes": "YEAH",
|
||||||
|
"no": "NOPE",
|
||||||
|
"about": "KITTE INFO",
|
||||||
|
"home-page-": "CAT HOME>",
|
||||||
|
"contributors": "GOOD PEEPL",
|
||||||
|
"developer": "H4CKR",
|
||||||
|
"translator": "LOLCAT",
|
||||||
|
"all-users-and-developers": "ALL LITL N BIG CATS",
|
||||||
|
"everyone-is-awesome": "YA LL AWSOM!!",
|
||||||
|
"license": "SERIOS THINY",
|
||||||
|
"exiting": "STOPIN…",
|
||||||
|
|
||||||
|
"dark-theme": "BLAK EYES",
|
||||||
|
"high-contrast": "WEAK EYES",
|
||||||
|
"welcome": "HAI THER!!",
|
||||||
|
"copyright-and-license": "SERIOS THINY",
|
||||||
|
"some-rights-reserved": "Some rights reserved.",
|
||||||
|
"ENTER": "ENTR",
|
||||||
|
"SPACE": "SPAC",
|
||||||
|
"ESCAPE": "ESC",
|
||||||
|
"TAB": "TAB",
|
||||||
|
"COMMA": "COMA",
|
||||||
|
"DOT": "DOT",
|
||||||
|
"to-enter-keyboard-mode-press-tab": "KEYBORD G33KS PRES TAB",
|
||||||
|
"usage-": "HOW TO USE>",
|
||||||
|
"positional-arguments-": "ARGS>",
|
||||||
|
"options-": "OPTS>",
|
||||||
|
"show-this-help-message": "SHOW WHAT YA LOOKIN NOW",
|
||||||
|
"do-nothing": "SLEEPY KITTE",
|
||||||
|
"scan-for-a-printer": "FIND A KITTE",
|
||||||
|
"text-printing-mode-with-options": "NO STEP PIC WANT MEOW",
|
||||||
|
"image-printing-options": "HOW TO STEP A PIC",
|
||||||
|
"convert-input-image-with-imagemagick": "HLP WITH ImageMagick",
|
||||||
|
"reset-configuration-": "RLY SCREW CFG?",
|
||||||
|
"brightness-": "BLAK OR WHITE>",
|
||||||
|
"text-printing-mode": "MEOW MEOW",
|
||||||
|
"internal-error-please-see-terminal": "ERR IN CONSOL PLZ SI",
|
||||||
|
"control-printer-thermal-strength": "HOW MUCH INK",
|
||||||
|
"strength-": "HOW MUCH INK>",
|
||||||
|
"or-drag-file-to-below": "THRW PIC OR MEOW HERE",
|
||||||
|
"reset": "STRT OVR",
|
||||||
|
"cat-face-toward": "WANT KITTE FACE NOT BUTT",
|
||||||
|
"quality-": "CAREFUL STEP>",
|
||||||
|
"print-quality": "HOW CAREFUL R STEPS",
|
||||||
|
"show-more-options": "LOT CFGS HERE",
|
||||||
|
"text-font": "PAW SHAP",
|
||||||
|
"text-size": "BIG OR SMAL",
|
||||||
|
"enter-text": "MEOW HERE",
|
||||||
|
"wrap-words-by-spaces": "NO HAF A WORD",
|
||||||
|
"minor-tweaks": "LITTL TRIKS",
|
||||||
|
"serif": "SHARP PAW",
|
||||||
|
"sans-serif": "SOFT PAW",
|
||||||
|
"monospace": "H4CKY PAW",
|
||||||
|
"rotate-image": "ROLL PIC"
|
||||||
|
}
|
@ -8,14 +8,12 @@
|
|||||||
"canvas": "画布",
|
"canvas": "画布",
|
||||||
"document": "文档",
|
"document": "文档",
|
||||||
"insert-picture": "插入图片",
|
"insert-picture": "插入图片",
|
||||||
|
"insert-text": "输入文本",
|
||||||
"help": "帮助",
|
"help": "帮助",
|
||||||
"javascript-license-information": "JavaScript 许可证信息",
|
"javascript-license-information": "JavaScript 许可证信息",
|
||||||
"settings": "设置",
|
"settings": "设置",
|
||||||
|
"image": "图像",
|
||||||
"threshold-": "阈值:",
|
"threshold-": "阈值:",
|
||||||
"transmission-speed-": "传输速度:",
|
|
||||||
"low": "低",
|
|
||||||
"moderate": "适中",
|
|
||||||
"high": "高",
|
|
||||||
"transparent-as-white": "透明为白色",
|
"transparent-as-white": "透明为白色",
|
||||||
"misc": "杂项",
|
"misc": "杂项",
|
||||||
"system": "系统",
|
"system": "系统",
|
||||||
@ -45,7 +43,6 @@
|
|||||||
"print-to-cat-printer": "打印到猫咪打印机。",
|
"print-to-cat-printer": "打印到猫咪打印机。",
|
||||||
"supported-models-": "支持的型号:",
|
"supported-models-": "支持的型号:",
|
||||||
"path-to-input-file-dash-for-stdin": "输入文件的位置。使用 '-' 作为标准输入",
|
"path-to-input-file-dash-for-stdin": "输入文件的位置。使用 '-' 作为标准输入",
|
||||||
"dump-the-traffic": "转储数据",
|
|
||||||
"please-install-pyobjc-via-pip": "请从 pip 安装 `pyobjc`",
|
"please-install-pyobjc-via-pip": "请从 pip 安装 `pyobjc`",
|
||||||
"please-install-bleak-via-pip": "请从 pip 安装 `bleak`",
|
"please-install-bleak-via-pip": "请从 pip 安装 `bleak`",
|
||||||
"folder-printer_lib-is-incomplete-or-missing-please-check": "文件夹 `printer_lib` 不完整或丢失,请检查",
|
"folder-printer_lib-is-incomplete-or-missing-please-check": "文件夹 `printer_lib` 不完整或丢失,请检查",
|
||||||
@ -85,7 +82,7 @@
|
|||||||
"contributors": "贡献者",
|
"contributors": "贡献者",
|
||||||
"developer": "开发者",
|
"developer": "开发者",
|
||||||
"translator": "翻译",
|
"translator": "翻译",
|
||||||
"all-testers-and-users": "所有测试及正式用户",
|
"all-users-and-developers": "每位用户及开发者",
|
||||||
"everyone-is-awesome": "每个人都是好样的!",
|
"everyone-is-awesome": "每个人都是好样的!",
|
||||||
"license": "许可证",
|
"license": "许可证",
|
||||||
"exiting": "退出中……",
|
"exiting": "退出中……",
|
||||||
@ -122,5 +119,14 @@
|
|||||||
"cat-face-toward": "猫脸朝上",
|
"cat-face-toward": "猫脸朝上",
|
||||||
"quality-": "质量:",
|
"quality-": "质量:",
|
||||||
"print-quality": "打印质量",
|
"print-quality": "打印质量",
|
||||||
"show-more-options": "显示更多选项"
|
"show-more-options": "显示更多选项",
|
||||||
|
"text-font": "字体",
|
||||||
|
"text-size": "大小",
|
||||||
|
"enter-text": "在此处输入文本",
|
||||||
|
"wrap-words-by-spaces": "空格处换行(不建议用于汉语)",
|
||||||
|
"minor-tweaks": "小优化",
|
||||||
|
"serif": "衬线字体",
|
||||||
|
"sans-serif": "无衬线字体",
|
||||||
|
"monospace": "等宽字体",
|
||||||
|
"rotate-image": "旋转图像"
|
||||||
}
|
}
|
81
www/main.css
81
www/main.css
@ -36,6 +36,9 @@ body {
|
|||||||
margin: 1em 0;
|
margin: 1em 0;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
body.android .hide-on-android {
|
body.android .hide-on-android {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -90,9 +93,12 @@ input[type="number"], input[type="text"] {
|
|||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
button:hover {
|
button:hover {
|
||||||
|
/*
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: var(--span) var(--span-double);
|
padding: var(--span) var(--span-double);
|
||||||
min-width: calc(6em + var(--span-double));
|
min-width: calc(6em + var(--span-double));
|
||||||
|
*/
|
||||||
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
button:active {
|
button:active {
|
||||||
box-shadow: 0 0 var(--span) inset var(--fore-color);
|
box-shadow: 0 0 var(--span) inset var(--fore-color);
|
||||||
@ -103,7 +109,6 @@ button:active {
|
|||||||
}
|
}
|
||||||
.label-span-input {
|
.label-span-input {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
box-sizing: border-box;
|
|
||||||
margin: var(--span-half) var(--span);
|
margin: var(--span-half) var(--span);
|
||||||
}
|
}
|
||||||
.label-span-input>:nth-child(1) {
|
.label-span-input>:nth-child(1) {
|
||||||
@ -119,7 +124,6 @@ button:active {
|
|||||||
}
|
}
|
||||||
.label-input-span {
|
.label-input-span {
|
||||||
display: block;
|
display: block;
|
||||||
box-sizing: border-box;
|
|
||||||
margin: var(--span-half) var(--span);
|
margin: var(--span-half) var(--span);
|
||||||
}
|
}
|
||||||
.label-input-span>:nth-child(1) {
|
.label-input-span>:nth-child(1) {
|
||||||
@ -173,11 +177,14 @@ main, header, footer {
|
|||||||
max-width: 45em;
|
max-width: 45em;
|
||||||
margin: 1em auto;
|
margin: 1em auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
.canvas-side {
|
.canvas-side {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
min-width: calc(var(--paper-width) + var(--border-double) + var(--span-double));
|
width: var(--paper-width);
|
||||||
|
margin: var(--span) calc((50% - var(--paper-width)) / 2);
|
||||||
}
|
}
|
||||||
.canvas-side>* {
|
.canvas-side>* {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -188,8 +195,9 @@ main, header, footer {
|
|||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* overflow: auto; */
|
/* overflow: auto; */
|
||||||
margin: var(--span);
|
margin: var(--span) 0;
|
||||||
min-width: 12em;
|
min-width: 20em;
|
||||||
|
/* width: 50%; */
|
||||||
}
|
}
|
||||||
.menu-side>.menu {
|
.menu-side>.menu {
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
@ -216,6 +224,7 @@ main, header, footer {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.compact-button:hover {
|
.compact-button:hover {
|
||||||
|
transform: unset;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 var(--span) calc(var(--span-double));
|
padding: 0 var(--span) calc(var(--span-double));
|
||||||
min-width: 6em;
|
min-width: 6em;
|
||||||
@ -249,9 +258,9 @@ main, header, footer {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: calc(var(--paper-width) + var(--border-double));
|
/* width: calc(var(--paper-width) + var(--border-double)); */
|
||||||
margin: var(--span);
|
width: var(--paper-width);
|
||||||
margin-bottom: 0;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin: var(--span) 0;
|
margin: var(--span) 0;
|
||||||
@ -263,7 +272,6 @@ p {
|
|||||||
.panel.active {
|
.panel.active {
|
||||||
height: calc(var(--panel-height) - var(--compact-menu-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: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.panel.sub.active {
|
.panel.sub.active {
|
||||||
@ -313,6 +321,11 @@ table#jslicense-labels1 {
|
|||||||
}
|
}
|
||||||
table#jslicense-labels1 td {
|
table#jslicense-labels1 td {
|
||||||
padding: var(--span-half) var(--span);
|
padding: var(--span-half) var(--span);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table#jslicense-labels1 td:nth-child(4) {
|
||||||
|
white-space: normal;
|
||||||
|
width: 50vw;
|
||||||
}
|
}
|
||||||
*:target {
|
*:target {
|
||||||
background-color: var(--target-color);
|
background-color: var(--target-color);
|
||||||
@ -335,7 +348,7 @@ hr {
|
|||||||
}
|
}
|
||||||
iframe#frame {
|
iframe#frame {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 12em;
|
height: 60vh;
|
||||||
border: none;
|
border: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
@ -355,33 +368,32 @@ iframe#frame {
|
|||||||
#dialog {
|
#dialog {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 16%;
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
opacity: 2;
|
opacity: 1;
|
||||||
transition: opacity var(--anim-time) var(--curve);
|
transition: opacity var(--anim-time) var(--curve);
|
||||||
}
|
}
|
||||||
#dialog>.content {
|
#dialog>.content {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
width: 40em;
|
width: 42em;
|
||||||
margin: auto;
|
max-height: 80vh;
|
||||||
box-sizing: border-box;
|
margin: 12vh auto;
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
transition: transform var(--anim-time) var(--curve);
|
transition: transform var(--anim-time) var(--curve);
|
||||||
transform-origin: center 33%;
|
transform-origin: center 33%;
|
||||||
}
|
}
|
||||||
#dialog.hidden {
|
#dialog.hidden {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
height: unset;
|
|
||||||
}
|
}
|
||||||
#dialog.hidden>.content {
|
#dialog.hidden>.content {
|
||||||
transform: scaleY(0);
|
transform: scaleY(0);
|
||||||
}
|
}
|
||||||
#dialog-content {
|
#dialog-content {
|
||||||
/* height: 12em; */
|
max-height: 60vh;
|
||||||
max-height: 640px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: var(--span);
|
padding: var(--span-double);
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -405,12 +417,12 @@ iframe#frame {
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
#select-language {
|
#select-language {
|
||||||
width: calc(100% - var(--span-double));
|
/* width: calc(100% - var(--span-double)); */
|
||||||
|
width: 12em;
|
||||||
height: 8em;
|
height: 8em;
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
padding: var(--span);
|
padding: var(--span);
|
||||||
margin: 0 var(--span);
|
margin: 0 var(--span);
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
#select-language option {
|
#select-language option {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -438,7 +450,7 @@ iframe#frame {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 1;
|
z-index: 3;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity var(--anim-time) var(--curve);
|
transition: opacity var(--anim-time) var(--curve);
|
||||||
}
|
}
|
||||||
@ -467,7 +479,7 @@ iframe#frame {
|
|||||||
height: var(--font-size);
|
height: var(--font-size);
|
||||||
margin: var(--font-size);
|
margin: var(--font-size);
|
||||||
background-color: var(--fore-color);
|
background-color: var(--fore-color);
|
||||||
border-radius: calc(var(--font-size) / 2);
|
border-radius: var(--font-size);
|
||||||
animation: jump 1s ease 0s infinite;
|
animation: jump 1s ease 0s infinite;
|
||||||
}
|
}
|
||||||
#loading-screen>.dots>span:nth-child(1) { animation-delay: 0s; }
|
#loading-screen>.dots>span:nth-child(1) { animation-delay: 0s; }
|
||||||
@ -519,6 +531,7 @@ a {
|
|||||||
#title { display: none; }
|
#title { display: none; }
|
||||||
.canvas-side {
|
.canvas-side {
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -530,7 +543,7 @@ a {
|
|||||||
.canvas-side>.buttons,
|
.canvas-side>.buttons,
|
||||||
.menu-side>.buttons {
|
.menu-side>.buttons {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: var(--compact-menu-height);
|
bottom: var(--span);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
@ -570,6 +583,9 @@ a {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
#dialog-content {
|
||||||
|
padding: var(--span) 0;
|
||||||
|
}
|
||||||
.blank {
|
.blank {
|
||||||
height: var(--compact-menu-height);
|
height: var(--compact-menu-height);
|
||||||
}
|
}
|
||||||
@ -656,19 +672,22 @@ body.high-contrast #notice * { border: var(--border) dashed var(--fore-color); }
|
|||||||
body.high-contrast a:any-link { color: #00f; }
|
body.high-contrast a:any-link { color: #00f; }
|
||||||
body.high-contrast #control-overlay { background-color: var(--shade); }
|
body.high-contrast #control-overlay { background-color: var(--shade); }
|
||||||
|
|
||||||
|
/*
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Unifont';
|
font-family: 'Unifont';
|
||||||
src: local('Unifont') url('unifont.ttf') url('unifont.otf');
|
src: local('Unifont') url('unifont.ttf') url('unifont.otf');
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
#insert-text-area {
|
#insert-text-area {
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
height: 50vh;
|
height: calc(60vh - 8em);
|
||||||
width: var(--paper-width);
|
width: var(--paper-width);
|
||||||
overflow: hidden auto;
|
overflow: hidden auto;
|
||||||
white-space: break-spaces;
|
white-space: break-spaces;
|
||||||
resize:none;
|
resize: none;
|
||||||
padding-top: .65ex;
|
padding-top: .65ex;
|
||||||
line-height: 1.25;
|
line-height: 1.25;
|
||||||
|
border: var(--border) solid currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-align-container span {
|
.text-align-container span {
|
||||||
@ -703,7 +722,7 @@ body.high-contrast #control-overlay { background-color: var(--shade); }
|
|||||||
.text-align-center { background-image: url("icons/text-center.svg")}
|
.text-align-center { background-image: url("icons/text-center.svg")}
|
||||||
.text-align-right { background-image: url("icons/text-right.svg")}
|
.text-align-right { background-image: url("icons/text-right.svg")}
|
||||||
|
|
||||||
input[name="wrap-by-space"] { margin-right: 5px; }
|
input[name="wrap-words-by-spaces"] { margin-right: 5px; }
|
||||||
#text-settings {
|
#text-settings {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -715,5 +734,5 @@ input[name="wrap-by-space"] { margin-right: 5px; }
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
label[name="wrap-by-space-label"] { padding-right: 2%; }
|
label[name="wrap-words-by-spaces-label"] { padding-right: 2%; }
|
||||||
#text-font { height: 100%; margin: 0px; }
|
#text-font { height: 100%; margin: 0px; }
|
244
www/main.js
244
www/main.js
@ -274,32 +274,38 @@ class CanvasController {
|
|||||||
canvas;
|
canvas;
|
||||||
imageUrl;
|
imageUrl;
|
||||||
algorithm;
|
algorithm;
|
||||||
_height;
|
algoElements;
|
||||||
_threshold;
|
textFont;
|
||||||
_energy;
|
textSize;
|
||||||
_thresholdRange;
|
textArea;
|
||||||
_energyRange;
|
|
||||||
transparentAsWhite;
|
transparentAsWhite;
|
||||||
previewData;
|
previewData;
|
||||||
|
rotate;
|
||||||
|
#height;
|
||||||
|
#threshold;
|
||||||
|
#energy;
|
||||||
|
#thresholdRange;
|
||||||
|
#energyRange;
|
||||||
|
#rotateCheck;
|
||||||
static defaultHeight = 384;
|
static defaultHeight = 384;
|
||||||
static defaultThreshold = 256 / 3;
|
static defaultThreshold = 256 / 3;
|
||||||
get threshold() {
|
get threshold() {
|
||||||
return this._threshold;
|
return this.#threshold;
|
||||||
}
|
}
|
||||||
set threshold(value) {
|
set threshold(value) {
|
||||||
this._threshold = this._thresholdRange.value = value;
|
this.#threshold = this.#thresholdRange.value = value;
|
||||||
}
|
}
|
||||||
get energy() {
|
get energy() {
|
||||||
return this._energy;
|
return this.#energy;
|
||||||
}
|
}
|
||||||
set energy(value) {
|
set energy(value) {
|
||||||
this._energy = this._energyRange.value = value;
|
this.#energy = this.#energyRange.value = value;
|
||||||
}
|
}
|
||||||
get height() {
|
get height() {
|
||||||
return this._height;
|
return this.#height;
|
||||||
}
|
}
|
||||||
set height(value) {
|
set height(value) {
|
||||||
this.canvas.height = this.preview.height = this._height = value;
|
this.canvas.height = this.preview.height = this.#height = value;
|
||||||
}
|
}
|
||||||
constructor() {
|
constructor() {
|
||||||
this.preview = document.getElementById('preview');
|
this.preview = document.getElementById('preview');
|
||||||
@ -308,13 +314,13 @@ class CanvasController {
|
|||||||
this.textSize = document.getElementById("text-size");
|
this.textSize = document.getElementById("text-size");
|
||||||
this.textFont = document.getElementById("text-font");
|
this.textFont = document.getElementById("text-font");
|
||||||
this.textArea = document.getElementById("insert-text-area");
|
this.textArea = document.getElementById("insert-text-area");
|
||||||
this.wrapBySpace = document.querySelector('input[name="wrap-by-space"]');
|
this.wrapBySpace = document.querySelector('input[name="wrap-words-by-spaces"]');
|
||||||
this.textAlgorithm = document.querySelector('input[name="algo"][value="algo-direct"]');
|
|
||||||
this.height = CanvasController.defaultHeight;
|
this.height = CanvasController.defaultHeight;
|
||||||
this._thresholdRange = document.querySelector('[name="threshold"]');
|
this.#thresholdRange = document.querySelector('[name="threshold"]');
|
||||||
this._energyRange = document.querySelector('[name="energy"]');
|
this.#energyRange = document.querySelector('[name="energy"]');
|
||||||
this.imageUrl = null;
|
this.imageUrl = null;
|
||||||
this.textAlign = "left";
|
this.textAlign = "left";
|
||||||
|
this.rotate = false;
|
||||||
|
|
||||||
for (let elem of document.querySelectorAll("input[name=text-align]")){
|
for (let elem of document.querySelectorAll("input[name=text-align]")){
|
||||||
if (elem.checked) { this.textAlign = elem.value; }
|
if (elem.checked) { this.textAlign = elem.value; }
|
||||||
@ -336,7 +342,7 @@ class CanvasController {
|
|||||||
};
|
};
|
||||||
file_reader.readAsText(event.dataTransfer.files[0]);
|
file_reader.readAsText(event.dataTransfer.files[0]);
|
||||||
} else {
|
} else {
|
||||||
this.insertPicture(event.dataTransfer.files);
|
this.useFiles(event.dataTransfer.files);
|
||||||
}
|
}
|
||||||
return prevent_default(event);
|
return prevent_default(event);
|
||||||
});
|
});
|
||||||
@ -345,8 +351,10 @@ class CanvasController {
|
|||||||
this.textArea.style["font-family"] = this.textFont.value;
|
this.textArea.style["font-family"] = this.textFont.value;
|
||||||
this.textArea.style["word-break"] = this.wrapBySpace.checked ? "break-word" : "break-all";
|
this.textArea.style["word-break"] = this.wrapBySpace.checked ? "break-word" : "break-all";
|
||||||
|
|
||||||
|
this.algoElements = document.querySelectorAll('input[name="algo"]');
|
||||||
|
|
||||||
putEvent('input[name="algo"]', 'change', (event) => this.useAlgorithm(event.currentTarget.value), this);
|
putEvent('input[name="algo"]', 'change', (event) => this.useAlgorithm(event.currentTarget.value), this);
|
||||||
putEvent('#insert-picture' , 'click', () => this.insertPicture(), this);
|
putEvent('#insert-picture' , 'click', () => this.useFiles(), this);
|
||||||
putEvent('#insert-text' , 'click', () => Dialog.alert("#text-input", () => this.insertText(this.textArea.value)));
|
putEvent('#insert-text' , 'click', () => Dialog.alert("#text-input", () => this.insertText(this.textArea.value)));
|
||||||
putEvent('#text-size' , 'change', () => this.textArea.style["font-size"] = this.textSize.value + "px");
|
putEvent('#text-size' , 'change', () => this.textArea.style["font-size"] = this.textSize.value + "px");
|
||||||
putEvent('#text-font' , 'change', () => this.textArea.style["font-family"] = this.textFont.value);
|
putEvent('#text-font' , 'change', () => this.textArea.style["font-family"] = this.textFont.value);
|
||||||
@ -354,11 +362,13 @@ class CanvasController {
|
|||||||
this.textAlign = event.currentTarget.value
|
this.textAlign = event.currentTarget.value
|
||||||
this.textArea.style["text-align"] = this.textAlign;
|
this.textArea.style["text-align"] = this.textAlign;
|
||||||
}, this);
|
}, this);
|
||||||
putEvent('input[name="wrap-by-space"]' , 'change', () => this.textArea.style["word-break"] = this.wrapBySpace.checked ? "break-word" : "break-all");
|
putEvent('input[name="wrap-words-by-spaces"]' , 'change', () => this.textArea.style["word-break"] = this.wrapBySpace.checked ? "break-word" : "break-all");
|
||||||
putEvent('#button-preview' , 'click', this.activatePreview , this);
|
putEvent('#button-preview' , 'click', this.activatePreview , this);
|
||||||
putEvent('#button-reset' , 'click', this.reset , this);
|
putEvent('#button-reset' , 'click', this.reset , this);
|
||||||
putEvent('#canvas-expand' , 'click', this.expand , this);
|
putEvent('#canvas-expand' , 'click', this.expand , this);
|
||||||
putEvent('#canvas-crop' , 'click', this.crop , this);
|
putEvent('#canvas-crop' , 'click', this.crop , this);
|
||||||
|
putEvent('[name="rotate"]' , 'change', e => this.setRotate(e.currentTarget.checked), this);
|
||||||
|
this.#rotateCheck = document.querySelector('[name="rotate"]');
|
||||||
|
|
||||||
putEvent('[name="threshold"]', 'change', (event) => {
|
putEvent('[name="threshold"]', 'change', (event) => {
|
||||||
this.threshold = parseInt(event.currentTarget.value);
|
this.threshold = parseInt(event.currentTarget.value);
|
||||||
@ -374,17 +384,27 @@ class CanvasController {
|
|||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
useAlgorithm(name) {
|
useAlgorithm(name) {
|
||||||
|
for (let e of this.algoElements) {
|
||||||
|
e.checked = e.value === name;
|
||||||
|
}
|
||||||
this.algorithm = name;
|
this.algorithm = name;
|
||||||
this.threshold = CanvasController.defaultThreshold;
|
this.threshold = CanvasController.defaultThreshold;
|
||||||
this._thresholdRange.dispatchEvent(new Event('change'));
|
this.#thresholdRange.dispatchEvent(new Event('change'));
|
||||||
this.energy = name == 'algo-direct' ? 96 : 64;
|
this.energy = name == 'algo-direct' ? 96 : 64;
|
||||||
this._energyRange.dispatchEvent(new Event('change'));
|
this.#energyRange.dispatchEvent(new Event('change'));
|
||||||
this.activatePreview();
|
this.activatePreview();
|
||||||
}
|
}
|
||||||
expand(length = CanvasController.defaultHeight) {
|
expand(length = CanvasController.defaultHeight) {
|
||||||
this.height += length;
|
this.height += length;
|
||||||
}
|
}
|
||||||
crop() {}
|
crop() {
|
||||||
|
// STUB
|
||||||
|
}
|
||||||
|
setRotate(value) {
|
||||||
|
this.#rotateCheck.checked = value;
|
||||||
|
this.rotate = value;
|
||||||
|
if (this.imageUrl !== null) this.putImage(this.imageUrl);
|
||||||
|
}
|
||||||
visualEnergy(amount) {
|
visualEnergy(amount) {
|
||||||
let rate = amount / 256;
|
let rate = amount / 256;
|
||||||
let brightness = Math.max(1.6 - rate * 1.5, 0.75),
|
let brightness = Math.max(1.6 - rate * 1.5, 0.75),
|
||||||
@ -437,46 +457,68 @@ class CanvasController {
|
|||||||
this.previewData = mono_data;
|
this.previewData = mono_data;
|
||||||
context_p.putImageData(new_data, 0, 0);
|
context_p.putImageData(new_data, 0, 0);
|
||||||
}
|
}
|
||||||
insertPicture(files) {
|
putImage(url) {
|
||||||
const put_image = (url) => {
|
let img = document.getElementById('img');
|
||||||
this.imageUrl = url;
|
img.src = url;
|
||||||
let img = document.createElement('img');
|
img.addEventListener('load', () => {
|
||||||
img.src = url;
|
let canvas = this.canvas;
|
||||||
hidden_area.appendChild(img);
|
let ctx = canvas.getContext('2d');
|
||||||
img.addEventListener('load', () => {
|
if (this.rotate) {
|
||||||
let canvas = this.canvas;
|
let intermediate_canvas = document.createElement('canvas');
|
||||||
let rate = img.height / img.width;
|
/**
|
||||||
this.height = canvas.width * rate;
|
* w h
|
||||||
let context = canvas.getContext('2d');
|
* +------+ +---+
|
||||||
context.drawImage(img, 0, 0, canvas.width, canvas.height);
|
* h | | | | w
|
||||||
this.crop();
|
* +------+ | | intermediate_canvas
|
||||||
this.activatePreview();
|
* canvas +---+
|
||||||
hint('#button-print');
|
*/
|
||||||
});
|
let w = canvas.width;
|
||||||
}
|
let h = this.height = Math.floor(canvas.width * img.width / img.height);
|
||||||
let use_files = (files) => {
|
intermediate_canvas.width = h;
|
||||||
|
intermediate_canvas.height = w;
|
||||||
|
let i_ctx = intermediate_canvas.getContext('2d');
|
||||||
|
i_ctx.drawImage(img, 0, 0, h, w);
|
||||||
|
let i_data = i_ctx.getImageData(0, 0, h, w);
|
||||||
|
let data = ctx.createImageData(w, h);
|
||||||
|
for (let j = 0; j < h; j++) {
|
||||||
|
for (let i = 0; i < w; i++) {
|
||||||
|
for (let d = 0; d < 4; d++)
|
||||||
|
data.data[(i * 4 + d) + (j * w * 4)] = i_data.data[(j * 4 + d) + ((w - i) * 4 * h)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.putImageData(data, 0, 0);
|
||||||
|
} else {
|
||||||
|
this.height = Math.floor(canvas.width * img.height / img.width);
|
||||||
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
this.crop();
|
||||||
|
this.activatePreview();
|
||||||
|
hint('#button-print');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
useFiles(files) {
|
||||||
|
const use_files = (files) => {
|
||||||
let file = files[0];
|
let file = files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
let url = URL.createObjectURL(file);
|
let url = URL.createObjectURL(file);
|
||||||
put_image(url);
|
this.imageUrl = url;
|
||||||
|
this.putImage(url);
|
||||||
this.controls.classList.add('hidden');
|
this.controls.classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (files) use_files(files);
|
if (files) { use_files(files); return; }
|
||||||
else {
|
document.querySelectorAll('.dummy').forEach(e => e.remove());
|
||||||
document.querySelectorAll('.dummy').forEach(e => e.remove());
|
let input = document.createElement('input');
|
||||||
let input = document.createElement('input');
|
input.classList.add('dummy');
|
||||||
input.classList.add('dummy');
|
input.type = 'file';
|
||||||
input.type = 'file';
|
input.accept = 'image/*';
|
||||||
input.accept = 'image/*';
|
input.addEventListener('change', () => {
|
||||||
input.addEventListener('change', () => {
|
use_files(input.files);
|
||||||
use_files(input.files);
|
});
|
||||||
});
|
hidden_area.appendChild(input);
|
||||||
hidden_area.appendChild(input);
|
input.click();
|
||||||
input.click();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
insertText(text) {
|
insertText(text) {
|
||||||
if (text == null || text.trim() == "") { return; }
|
if (text == null || text.trim() == "") { return false; }
|
||||||
|
|
||||||
const text_size = parseInt(this.textSize.value);
|
const text_size = parseInt(this.textSize.value);
|
||||||
const text_font = this.textFont.value;
|
const text_font = this.textFont.value;
|
||||||
@ -550,12 +592,12 @@ class CanvasController {
|
|||||||
|
|
||||||
this.crop();
|
this.crop();
|
||||||
|
|
||||||
this.textAlgorithm.checked = true;
|
this.useAlgorithm('algo-direct');
|
||||||
this.textAlgorithm.dispatchEvent(new Event("change"));
|
this.threshold = 16;
|
||||||
|
|
||||||
this.imageUrl = this.canvas.toDataURL();
|
this.setRotate(false);
|
||||||
this.activatePreview();
|
this.putImage(this.imageUrl = this.canvas.toDataURL());
|
||||||
|
|
||||||
this.controls.classList.add('hidden');
|
this.controls.classList.add('hidden');
|
||||||
|
|
||||||
hint('#button-print');
|
hint('#button-print');
|
||||||
@ -597,7 +639,7 @@ function applyI18nToDom(doc) {
|
|||||||
async function initI18n(current_language) {
|
async function initI18n(current_language) {
|
||||||
if (typeof i18n === 'undefined') return;
|
if (typeof i18n === 'undefined') return;
|
||||||
/** @type {HTMLSelectElement} */
|
/** @type {HTMLSelectElement} */
|
||||||
let language_options = document.getElementById('select-language');
|
let language_select = document.getElementById('select-language');
|
||||||
/** @type {{ [code: string]: string }} */
|
/** @type {{ [code: string]: string }} */
|
||||||
let list = await fetch('/lang/list.json').then(r => r.json());
|
let list = await fetch('/lang/list.json').then(r => r.json());
|
||||||
let use_language = async (value) => {
|
let use_language = async (value) => {
|
||||||
@ -605,6 +647,7 @@ async function initI18n(current_language) {
|
|||||||
i18n.add(value, await fetch(`/lang/${value}.json`).then(r => r.json()), true);
|
i18n.add(value, await fetch(`/lang/${value}.json`).then(r => r.json()), true);
|
||||||
applyI18nToDom();
|
applyI18nToDom();
|
||||||
}
|
}
|
||||||
|
language_select.addEventListener('change', () => use_language(language_select.value));
|
||||||
for (let code in list) {
|
for (let code in list) {
|
||||||
let option = document.createElement('option');
|
let option = document.createElement('option');
|
||||||
option.value = code;
|
option.value = code;
|
||||||
@ -614,22 +657,22 @@ async function initI18n(current_language) {
|
|||||||
let option = event.currentTarget;
|
let option = event.currentTarget;
|
||||||
let value = option.value;
|
let value = option.value;
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
language_options.selectedIndex = option.index;
|
language_select.selectedIndex = option.index;
|
||||||
use_language(value);
|
use_language(value);
|
||||||
Notice.note('welcome');
|
Notice.note('welcome');
|
||||||
});
|
});
|
||||||
language_options.appendChild(option);
|
language_select.appendChild(option);
|
||||||
}
|
}
|
||||||
if (!navigator.languages) {
|
if (!navigator.languages) {
|
||||||
if (!navigator.language) return;
|
if (!navigator.language) return;
|
||||||
else navigator.languages = [navigator.language, 'en-US'];
|
else navigator.languages = [navigator.language, 'en-US'];
|
||||||
}
|
}
|
||||||
if (current_language) {
|
if (current_language) {
|
||||||
for (let option of language_options.children)
|
for (let option of language_select.children)
|
||||||
if (option.value === current_language)
|
if (option.value === current_language)
|
||||||
option.click();
|
option.click();
|
||||||
} else for (let code of navigator.languages)
|
} else for (let code of navigator.languages)
|
||||||
if (list[code]) for (let option of language_options.children)
|
if (list[code]) for (let option of language_select.children)
|
||||||
if (option.value === code) {
|
if (option.value === code) {
|
||||||
option.setAttribute('data-default', '');
|
option.setAttribute('data-default', '');
|
||||||
if (!current_language) option.click();
|
if (!current_language) option.click();
|
||||||
@ -697,22 +740,22 @@ class Main {
|
|||||||
await initI18n(this.settings['language']);
|
await initI18n(this.settings['language']);
|
||||||
|
|
||||||
this.canvasController = new CanvasController();
|
this.canvasController = new CanvasController();
|
||||||
putEvent('#button-exit', 'click', () => this.exit(false), this);
|
putEvent('#button-exit' , 'click', () => this.exit(false), this);
|
||||||
putEvent('#button-exit', 'contextmenu',
|
putEvent('#button-print' , 'click', this.print, this);
|
||||||
(event) => (event.preventDefault(), this.exit(true)), this);
|
putEvent('#device-refresh' , 'click', this.searchDevices, this);
|
||||||
putEvent('#button-print', 'click', this.print, this);
|
putEvent('#button-exit' , 'contextmenu', (event) => (event.preventDefault(), this.exit(true)), this);
|
||||||
putEvent('#device-refresh', 'click', this.searchDevices, this);
|
|
||||||
putEvent('#set-accessibility', 'click', () => Dialog.alert('#accessibility'));
|
putEvent('#set-accessibility', 'click', () => Dialog.alert('#accessibility'));
|
||||||
this.attachSetter('#device-options', 'input', 'printer',
|
this.attachSetter('#device-options', 'input', 'printer',
|
||||||
(value) => callApi('/connect', { device: value })
|
(value) => callApi('/connect', { device: value })
|
||||||
);
|
);
|
||||||
putEvent('a[target="frame"]', 'click', () => Dialog.alert('#frame'));
|
putEvent('a[target="frame"]', 'click', () => Dialog.alert('#frame'));
|
||||||
this.attachSetter('[name="scan-time"]', 'change', 'scan_timeout');
|
this.attachSetter('[name="scan-time"]' , 'change', 'scan_timeout');
|
||||||
this.attachSetter('input[name="algo"]', 'change', 'mono_algorithm',
|
this.attachSetter('[name="rotate"]' , 'change', 'rotate');
|
||||||
|
this.attachSetter('input[name="algo"]' , 'change', 'mono_algorithm',
|
||||||
(value) => this.settings['text_mode'] = (value === 'algo-direct')
|
(value) => this.settings['text_mode'] = (value === 'algo-direct')
|
||||||
);
|
);
|
||||||
this.attachSetter('[name="transparent-as-white"]', 'change', 'transparent_as_white');
|
this.attachSetter('[name="transparent-as-white"]', 'change', 'transparent_as_white');
|
||||||
this.attachSetter('[name="wrap-by-space"]', 'change', 'wrap_by_space');
|
this.attachSetter('[name="wrap-words-by-spaces"]', 'change', 'wrap_by_space');
|
||||||
this.attachSetter('[name="dry-run"]', 'change', 'dry_run',
|
this.attachSetter('[name="dry-run"]', 'change', 'dry_run',
|
||||||
(checked) => checked && Notice.note('dry-run-test-print-process-only')
|
(checked) => checked && Notice.note('dry-run-test-print-process-only')
|
||||||
);
|
);
|
||||||
@ -731,16 +774,13 @@ class Main {
|
|||||||
this.attachSetter('[name="high-contrast"]', 'change', 'high_contrast',
|
this.attachSetter('[name="high-contrast"]', 'change', 'high_contrast',
|
||||||
(checked) => apply_class('high-contrast', checked)
|
(checked) => apply_class('high-contrast', checked)
|
||||||
);
|
);
|
||||||
this.attachSetter('[name="threshold"]', 'change', 'threshold');
|
this.attachSetter('[name="threshold"]' , 'change', 'threshold');
|
||||||
this.attachSetter('[name="energy"]', 'change', 'energy');
|
this.attachSetter('[name="energy"]' , 'change', 'energy');
|
||||||
this.attachSetter('[name="quality"]', 'change', 'quality');
|
this.attachSetter('[name="quality"]' , 'change', 'quality');
|
||||||
this.attachSetter('[name="flip"]', 'change', 'flip');
|
this.attachSetter('[name="flip"]' , 'change', 'flip');
|
||||||
// this.attachSetter('[name="flip-h"]', 'change', 'flip_h');
|
|
||||||
// this.attachSetter('[name="flip-v"]', 'change', 'flip_v');
|
|
||||||
// this.attachSetter('[name="dump"]', 'change', 'dump');
|
|
||||||
await this.activateConfig();
|
await this.activateConfig();
|
||||||
// one exception
|
// one exception
|
||||||
this.attachSetter('#select-language option', 'click', 'language');
|
this.attachSetter('#select-language', 'change', 'language');
|
||||||
|
|
||||||
if (this.settings['is_android']) {
|
if (this.settings['is_android']) {
|
||||||
document.body.classList.add('android');
|
document.body.classList.add('android');
|
||||||
@ -856,24 +896,29 @@ class Main {
|
|||||||
Notice.note('you-can-close-this-page-manually');
|
Notice.note('you-can-close-this-page-manually');
|
||||||
}
|
}
|
||||||
/** @param {Response} response */
|
/** @param {Response} response */
|
||||||
async bluetoothProblemHandler(response) {
|
async handleBluetoothProblem(response) {
|
||||||
// Not complete yet, it's different across other platforms
|
// Not complete yet, it's different across other platforms
|
||||||
let error_details = await response.json();
|
let error_details = await response.json();
|
||||||
if (
|
if (
|
||||||
error_details.name === 'org.bluez.Error.NotReady' ||
|
error_details.name === 'org.bluez.Error.NotReady' ||
|
||||||
error_details.name === 'org.freedesktop.DBus.Error.UnknownObject' ||
|
error_details.name === 'org.freedesktop.DBus.Error.UnknownObject' ||
|
||||||
|
error_details.name === 'org.bluez.Error.NotReady' ||
|
||||||
error_details.details.includes('not turned on') ||
|
error_details.details.includes('not turned on') ||
|
||||||
error_details.details.includes('WinError -2147020577')
|
error_details.details.includes('WinError -2147020577')
|
||||||
) Notice.warn('please-enable-bluetooth');
|
) Notice.warn('please-enable-bluetooth');
|
||||||
else if (
|
else if (
|
||||||
error_details.details.includes('no running event loop')
|
error_details.details.includes('no running event loop')
|
||||||
) Notice.error('internal-error-please-see-terminal');
|
) Notice.error('internal-error-please-see-terminal');
|
||||||
else throw new Error('Unknown Bluetooth Problem');
|
else
|
||||||
|
ErrorHandler.report(
|
||||||
|
new Error('API Failure'),
|
||||||
|
JSON.stringify(await response.json(), undefined, 4)
|
||||||
|
)
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
async searchDevices() {
|
async searchDevices() {
|
||||||
Notice.wait('scanning-for-devices');
|
Notice.wait('scanning-for-devices');
|
||||||
let search_result = await callApi('/devices', null, this.bluetoothProblemHandler);
|
let search_result = await callApi('/devices', null, this.handleBluetoothProblem);
|
||||||
if (search_result === null) return false;
|
if (search_result === null) return false;
|
||||||
let devices = search_result.devices;
|
let devices = search_result.devices;
|
||||||
Array.from(this.deviceOptions.children).forEach(e => e.remove());
|
Array.from(this.deviceOptions.children).forEach(e => e.remove());
|
||||||
@ -901,23 +946,18 @@ class Main {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: this.canvasController.makePbm()
|
body: this.canvasController.makePbm()
|
||||||
}).then(async (response) => {
|
}).then(async (response) => {
|
||||||
if (response.ok) Notice.note('finished')
|
if (response.ok) { Notice.note('finished'); return; }
|
||||||
else {
|
let json = response.json();
|
||||||
let json = response.json();
|
response.json = () => json;
|
||||||
response.json = () => json;
|
let error_data = await response.json();
|
||||||
let error_data = await response.json();
|
if (/address.+not found|Not connected/.test(error_data.details) ||
|
||||||
if (/address.+not found|Not connected/.test(error_data.details) ||
|
error_data.name === 'EOFError') {
|
||||||
error_data.name === 'EOFError') {
|
if (await this.searchDevices()) this.print();
|
||||||
if (await this.searchDevices()) this.print();
|
else Notice.error('please-check-if-the-printer-is-down');
|
||||||
else Notice.error('please-check-if-the-printer-is-down');
|
} else if (error_data.name === 'no-available-devices-found')
|
||||||
} else if (error_data.name === 'no-available-devices-found')
|
Notice.warn('no-available-devices-found');
|
||||||
Notice.warn('no-available-devices-found');
|
else
|
||||||
else
|
this.handleBluetoothProblem(response);
|
||||||
ErrorHandler.report(
|
|
||||||
new Error('API Failure'),
|
|
||||||
JSON.stringify(await response.json(), undefined, 4)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user