mirror of
https://github.com/Ircama/epson_print_conf.git
synced 2024-10-18 01:00:36 -04:00
Improvements
This commit is contained in:
parent
b9048b5bcd
commit
58dbd5cfd8
6 changed files with 136 additions and 72 deletions
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
|
@ -23,6 +23,7 @@ jobs:
|
|||
python -m pip install --upgrade pip
|
||||
#pip install git+https://github.com/pyinstaller/pyinstaller@develop
|
||||
pip install pyinstaller
|
||||
pip install Pillow
|
||||
pip install -r requirements.txt
|
||||
|
||||
- name: Run PyInstaller to create epson_print_conf.exe
|
||||
|
@ -30,9 +31,9 @@ jobs:
|
|||
python -m PyInstaller epson_print_conf.spec -- --default
|
||||
|
||||
- name: Zip the epson_print_conf.exe asset to epson_print_conf.zip
|
||||
run: >
|
||||
powershell -Command Compress-Archive dist/epson_print_conf.exe
|
||||
dist/epson_print_conf.zip
|
||||
run: |
|
||||
Compress-Archive dist/epson_print_conf.exe dist/epson_print_conf.zip
|
||||
shell: pwsh
|
||||
|
||||
- name: Generate Changelog
|
||||
run: >
|
||||
|
|
18
README.md
18
README.md
|
@ -212,27 +212,21 @@ pyinstaller epson_print_conf.spec -- --default
|
|||
|
||||
Then run the executable file created in the *dist/* folder, which has the same options of `ui.py`.
|
||||
|
||||
An alternative way to create the executable file from *ui.py* without using *epson_print_conf.spec* is the following:
|
||||
|
||||
```bash
|
||||
pyinstaller --onefile ui.py --name epson_print_conf --hidden-import babel.numbers --windowed
|
||||
```
|
||||
|
||||
A file named *gui.py* is also included (similar to *ui.py*), which automatically loads a previously created configuration file that has to be named *printer_conf.pickle*, merging it with the program configuration. (See below the *parse_devices.py* utility.) To build the executable program with this file instead of the default *ui.py*, run the following command:
|
||||
It is also possible to automatically load a previously created configuration file that has to be named *epson_print_conf.pickle*, merging it with the program configuration. (See below the *parse_devices.py* utility.) To build the executable program with this file, run the following command:
|
||||
|
||||
```bash
|
||||
pip install pyinstaller # if not yet installed
|
||||
curl -o devices.xml https://codeberg.org/attachments/147f41a3-a6ea-45f6-8c2a-25bac4495a1d
|
||||
python3 parse_devices.py -a 192.168.178.29 -s XP-205 -p printer_conf.pickle # use your default IP address and printer model as default settings for the GUI
|
||||
python3 parse_devices.py -a 192.168.178.29 -s XP-205 -p epson_print_conf.pickle # use your default IP address and printer model as default settings for the GUI
|
||||
pyinstaller epson_print_conf.spec
|
||||
```
|
||||
|
||||
When the build operation is completed, you can run the executable program created in the *dist/* folder. It does not have options, embeds the *printer_conf.pickle* file and starts with the default IP address and printer model defined in the build phase.
|
||||
|
||||
This repository includes a Windows *epson_print_conf.exe* executable file which is automatically generated by a [GitHub Action](.github/workflows/build.yml). It is packaged in a ZIP file named *epson_print_conf.zip* and uploaded into the [Releases](https://github.com/Ircama/epson_print_conf/releases/latest) folder.
|
||||
When embedding *epson_print_conf.pickle*, the created program does not have options and starts with the default IP address and printer model defined in the build phase.
|
||||
|
||||
As mentioned in the [documentation](https://pyinstaller.org/en/stable/), PyInstaller supports Windows, MacOS X, Linux and other UNIX Operating Systems. It creates an executable file which is only compatible with the operating system that is used to build the asset.
|
||||
|
||||
This repository includes a Windows *epson_print_conf.exe* executable file which is automatically generated by a [GitHub Action](.github/workflows/build.yml). It is packaged in a ZIP file named *epson_print_conf.zip* and uploaded into the [Releases](https://github.com/Ircama/epson_print_conf/releases/latest) folder.
|
||||
|
||||
## Utilities and notes
|
||||
|
||||
### parse_devices.py
|
||||
|
@ -291,6 +285,8 @@ Generate printer configuration from devices.xml
|
|||
|
||||
The output is better formatted when also installing [black](https://pypi.org/project/black/).
|
||||
|
||||
The program does not provide *printer_head_id* and *Power off timer*.
|
||||
|
||||
### find_printers.py
|
||||
|
||||
*find_printers.py* can be executed via `python find_printers.py` and prints the list of the discovered printers to the standard output. It is internally used as a library by *ui.py*.
|
||||
|
|
|
@ -719,29 +719,13 @@ class EpsonPrinter:
|
|||
else:
|
||||
destination[key] = value
|
||||
return destination
|
||||
# process "alias" definintion
|
||||
|
||||
if conf_dict:
|
||||
self.expand_printer_conf(conf_dict)
|
||||
if conf_dict and replace_conf:
|
||||
self.PRINTER_CONFIG = conf_dict
|
||||
for printer_name, printer_data in self.PRINTER_CONFIG.copy().items():
|
||||
if "alias" in printer_data:
|
||||
aliases = printer_data["alias"]
|
||||
del printer_data["alias"]
|
||||
if not isinstance(aliases, list):
|
||||
logging.error(
|
||||
"Alias '%s' of printer '%s' in configuration "
|
||||
"must be a list.",
|
||||
aliases, printer_name
|
||||
)
|
||||
continue
|
||||
for alias_name in aliases:
|
||||
if alias_name in self.PRINTER_CONFIG:
|
||||
logging.error(
|
||||
"Alias '%s' of printer '%s' is already defined "
|
||||
"in configuration.",
|
||||
alias_name, printer_name
|
||||
)
|
||||
else:
|
||||
self.PRINTER_CONFIG[alias_name] = printer_data
|
||||
self.expand_printer_conf(self.PRINTER_CONFIG)
|
||||
if conf_dict and not replace_conf:
|
||||
self.PRINTER_CONFIG = merge(self.PRINTER_CONFIG, conf_dict)
|
||||
for key, values in self.PRINTER_CONFIG.items():
|
||||
|
@ -752,22 +736,6 @@ class EpsonPrinter:
|
|||
]
|
||||
if not values['alias']:
|
||||
del values['alias']
|
||||
# process "same-as" definintion
|
||||
for printer_name, printer_data in self.PRINTER_CONFIG.copy().items():
|
||||
if "same-as" in printer_data:
|
||||
sameas = printer_data["same-as"]
|
||||
#del printer_data["same-as"]
|
||||
if sameas in self.PRINTER_CONFIG:
|
||||
self.PRINTER_CONFIG[printer_name] = {
|
||||
**self.PRINTER_CONFIG[sameas],
|
||||
**printer_data
|
||||
}
|
||||
else:
|
||||
logging.error(
|
||||
"Undefined 'same-as' printer '%s' "
|
||||
"in '%s' configuration.",
|
||||
sameas, printer_name
|
||||
)
|
||||
self.model = model
|
||||
self.hostname = hostname
|
||||
self.port = port
|
||||
|
@ -793,6 +761,48 @@ class EpsonPrinter:
|
|||
"""Return list of available information methods about a printer."""
|
||||
return(filter(lambda x: x.startswith("get_"), dir(self)))
|
||||
|
||||
def expand_printer_conf(self, conf):
|
||||
"""
|
||||
Expand "alias" and "same-as" of a printer database for all printers
|
||||
"""
|
||||
# process "alias" definintion
|
||||
for printer_name, printer_data in conf.copy().items():
|
||||
if "alias" in printer_data:
|
||||
aliases = printer_data["alias"]
|
||||
del printer_data["alias"]
|
||||
if not isinstance(aliases, list):
|
||||
logging.error(
|
||||
"Alias '%s' of printer '%s' in configuration "
|
||||
"must be a list.",
|
||||
aliases, printer_name
|
||||
)
|
||||
continue
|
||||
for alias_name in aliases:
|
||||
if alias_name in conf:
|
||||
logging.error(
|
||||
"Alias '%s' of printer '%s' is already defined "
|
||||
"in configuration.",
|
||||
alias_name, printer_name
|
||||
)
|
||||
else:
|
||||
conf[alias_name] = printer_data
|
||||
# process "same-as" definintion
|
||||
for printer_name, printer_data in conf.copy().items():
|
||||
if "same-as" in printer_data:
|
||||
sameas = printer_data["same-as"]
|
||||
#del printer_data["same-as"]
|
||||
if sameas in conf:
|
||||
conf[printer_name] = {
|
||||
**conf[sameas],
|
||||
**printer_data
|
||||
}
|
||||
else:
|
||||
logging.error(
|
||||
"Undefined 'same-as' printer '%s' "
|
||||
"in '%s' configuration.",
|
||||
sameas, printer_name
|
||||
)
|
||||
|
||||
def stats(self):
|
||||
"""Return all available information about a printer."""
|
||||
stat_set = {}
|
||||
|
|
|
@ -1,17 +1,70 @@
|
|||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import os.path
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
|
||||
def create_image(png_file, text):
|
||||
img = Image.new('RGB', (800, 150), color='black')
|
||||
fnt = ImageFont.truetype('arialbd.ttf', 30)
|
||||
d = ImageDraw.Draw(img)
|
||||
shadow_offset = 2
|
||||
bbox = d.textbbox((0, 0), text, font=fnt)
|
||||
x, y = (800-bbox[2])/2, (150-bbox[3])/2
|
||||
d.text((x+shadow_offset, y+shadow_offset), text, font=fnt, fill='gray')
|
||||
d.text((x, y), text, font=fnt, fill='#baf8f8')
|
||||
img.save(png_file, 'PNG')
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--default", action="store_true")
|
||||
options = parser.parse_args()
|
||||
|
||||
PROGRAM = [ 'gui.py' ]
|
||||
DATAS = [('printer_conf.pickle', '.')]
|
||||
BASENAME = 'epson_print_conf'
|
||||
|
||||
DATAS = [(BASENAME + '.pickle', '.')]
|
||||
SPLASH_IMAGE = BASENAME + '.png'
|
||||
|
||||
create_image(
|
||||
SPLASH_IMAGE, 'Epson Printer Configuration tool loading...'
|
||||
)
|
||||
|
||||
if not options.default and not os.path.isfile(DATAS[0][0]):
|
||||
print("\nMissing file", DATAS[0][0], "without using the default option.")
|
||||
quit()
|
||||
|
||||
gui_wrapper = """import pyi_splash
|
||||
import pickle
|
||||
from ui import EpsonPrinterUI
|
||||
from os import path
|
||||
|
||||
path_to_pickle = path.abspath(
|
||||
path.join(path.dirname(__file__), '""" + DATAS[0][0] + """')
|
||||
)
|
||||
with open(path_to_pickle, 'rb') as fp:
|
||||
conf_dict = pickle.load(fp)
|
||||
app = EpsonPrinterUI(conf_dict=conf_dict, replace_conf=False)
|
||||
pyi_splash.close()
|
||||
app.mainloop()
|
||||
"""
|
||||
|
||||
if options.default:
|
||||
PROGRAM = [ 'ui.py' ]
|
||||
DATAS = []
|
||||
gui_wrapper = """import pyi_splash
|
||||
import pickle
|
||||
from ui import main
|
||||
from os import path
|
||||
|
||||
app = main()
|
||||
pyi_splash.close()
|
||||
app.mainloop()
|
||||
"""
|
||||
|
||||
with open(PROGRAM[0], 'w') as file:
|
||||
file.write(gui_wrapper)
|
||||
|
||||
a = Analysis(
|
||||
PROGRAM,
|
||||
|
@ -28,27 +81,39 @@ a = Analysis(
|
|||
)
|
||||
|
||||
pyz = PYZ(a.pure)
|
||||
splash = Splash(
|
||||
SPLASH_IMAGE,
|
||||
binaries=a.binaries,
|
||||
datas=a.datas,
|
||||
text_pos=None,
|
||||
text_size=12,
|
||||
minify_script=True,
|
||||
always_on_top=True,
|
||||
)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
splash,
|
||||
splash.binaries,
|
||||
[],
|
||||
name='epson_print_conf',
|
||||
name=BASENAME,
|
||||
debug=False, # Setting to True gives you progress messages from the executable (for console=False there will be annoying MessageBoxes on Windows).
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
# console=False, # On Windows or Mac OS governs whether to use the console executable or the windowed executable. Always True on Linux/Unix (always console executable - it does not matter there).
|
||||
console=options.default, # On Windows or Mac OS governs whether to use the console executable or the windowed executable. Always True on Linux/Unix (always console executable - it does not matter there).
|
||||
disable_windowed_traceback=False, # Disable traceback dump of unhandled exception in windowed (noconsole) mode (Windows and macOS only)
|
||||
# hide_console='hide-early', # Windows only. In console-enabled executable, hide or minimize the console window ('hide-early', 'minimize-early', 'hide-late', 'minimize-late')
|
||||
hide_console='hide-early', # Windows only. In console-enabled executable, hide or minimize the console window ('hide-early', 'minimize-early', 'hide-late', 'minimize-late')
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
|
||||
os.remove(SPLASH_IMAGE)
|
||||
os.remove(PROGRAM[0])
|
||||
|
|
11
gui.py
11
gui.py
|
@ -1,11 +0,0 @@
|
|||
import pickle
|
||||
from ui import EpsonPrinterUI
|
||||
from os import path
|
||||
|
||||
PICKLE_CONF_FILE = "printer_conf.pickle"
|
||||
|
||||
path_to_pickle = path.abspath(path.join(path.dirname(__file__), PICKLE_CONF_FILE))
|
||||
with open(path_to_pickle, 'rb') as fp:
|
||||
conf_dict = pickle.load(fp)
|
||||
app = EpsonPrinterUI(conf_dict=conf_dict, replace_conf=False)
|
||||
app.mainloop()
|
9
ui.py
9
ui.py
|
@ -942,7 +942,7 @@ class EpsonPrinterUI(tk.Tk):
|
|||
self.clipboard_append(item_text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main():
|
||||
import argparse
|
||||
import pickle
|
||||
|
||||
|
@ -972,9 +972,12 @@ if __name__ == "__main__":
|
|||
if args.pickle:
|
||||
conf_dict = pickle.load(args.pickle[0])
|
||||
|
||||
app = EpsonPrinterUI(conf_dict=conf_dict, replace_conf=args.override)
|
||||
return EpsonPrinterUI(conf_dict=conf_dict, replace_conf=args.override)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
app.mainloop()
|
||||
main().mainloop()
|
||||
except:
|
||||
print("\nInterrupted.")
|
||||
sys.exit(0)
|
||||
|
|
Loading…
Reference in a new issue