mirror of
https://github.com/1j01/textual-paint.git
synced 2024-11-28 10:03:29 +03:00
Rasterize before setting as wallpaper
This makes Set As Wallpaper work on Windows 10 and macOS 10.14
This commit is contained in:
parent
ebbab737d4
commit
fece1c48c6
@ -197,7 +197,7 @@ To preview ANSI art files in file managers like Nautilus, Thunar, Nemo, or Caja,
|
||||
- Free-Form Select stamping/finalizing is incorrect when the selection is off-screen to the left or top.
|
||||
- Status bar description can be left blank when selecting a menu item. (I think the `Leave` event can come after closing, once the mouse moves.)
|
||||
- Menu items like Copy/Cut/Paste are not grayed out when inapplicable. Only unimplemented items are grayed out.
|
||||
- Set As Wallpaper may not work on your system. For me, on Ubuntu, the wallpaper setting is updated but the picture is not, unless I manually pick it. There is however untested support for many platforms, and you may have better luck than me.
|
||||
- Set As Wallpaper may not work on your system. It works for me on Windows 10, and macOS 10.14, but on Ubuntu 22, the wallpaper setting is updated but the picture is not, unless I manually pick it. There is also untested support for many other platforms.
|
||||
- ANSI files (.ans) are treated as UTF-8 when saving and loading, rather than CP437 or Windows-1252 or any other encodings. Unicode is nice and modern terminals support it, but it's not the standard for ANSI files. There isn't really a standard for ANSI files.
|
||||
- ANSI files are loaded with a white background. This may make sense as a default for text files, but ANSI files either draw a background or assume a black background, being designed for terminals.
|
||||
- Hitting Enter in View Bitmap mode exits the mode but may also trigger a menu item. Menu items ought to be disabled when hidden, and View Bitmap should prevent the key event from taking other actions if possible.
|
||||
|
@ -33,6 +33,7 @@
|
||||
"Caja",
|
||||
"clion",
|
||||
"cmdpxl",
|
||||
"Consolas",
|
||||
"dasharray",
|
||||
"Deutsch",
|
||||
"DIALOGEX",
|
||||
@ -57,17 +58,20 @@
|
||||
"hsrgb",
|
||||
"humbnail",
|
||||
"icns",
|
||||
"Inconsolata",
|
||||
"Intelli",
|
||||
"linewrap",
|
||||
"𝗟𝙇",
|
||||
"llpaper",
|
||||
"lrgb",
|
||||
"Lucida",
|
||||
"mirc",
|
||||
"modd",
|
||||
"mspaint",
|
||||
"mvim",
|
||||
"myusername",
|
||||
"Nemo",
|
||||
"Noto",
|
||||
"Odhner",
|
||||
"pagedown",
|
||||
"pageup",
|
||||
|
@ -41,6 +41,7 @@ from .windows import Window, DialogWindow, CharacterSelectorDialogWindow, Messag
|
||||
from .file_dialogs import SaveAsDialogWindow, OpenDialogWindow
|
||||
from .edit_colors import EditColorsDialogWindow
|
||||
from .localization.i18n import get as _, load_language, remove_hotkey
|
||||
from .rasterize_ansi_art import rasterize
|
||||
from .wallpaper import get_config_dir, set_wallpaper
|
||||
from .auto_restart import restart_on_changes, restart_program
|
||||
|
||||
@ -3562,10 +3563,13 @@ Columns: {len(palette) // 2}
|
||||
try:
|
||||
dir = os.path.join(get_config_dir("textual-paint"), "wallpaper")
|
||||
os.makedirs(dir, exist_ok=True)
|
||||
svg = self.image.get_svg()
|
||||
image_path = os.path.join(dir, "wallpaper.svg")
|
||||
with open(image_path, "w", encoding="utf-8") as f:
|
||||
f.write(svg)
|
||||
# svg = self.image.get_svg()
|
||||
# image_path = os.path.join(dir, "wallpaper.svg")
|
||||
# with open(image_path, "w", encoding="utf-8") as f:
|
||||
# f.write(svg)
|
||||
image_path = os.path.join(dir, "wallpaper.png")
|
||||
pil_image = rasterize(self.image)
|
||||
pil_image.save(image_path)
|
||||
set_wallpaper(image_path)
|
||||
except Exception as e:
|
||||
self.message_box(_("Paint"), _("Failed to set the wallpaper."), "ok", error=e)
|
||||
|
91
src/textual_paint/rasterize_ansi_art.py
Normal file
91
src/textual_paint/rasterize_ansi_art.py
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from textual_paint.paint import AnsiArtDocument
|
||||
|
||||
# load font
|
||||
# font = ImageFont.truetype('fonts/ansi.ttf', size=16, layout_engine=ImageFont.Layout.BASIC)
|
||||
# font = ImageFont.load_default()
|
||||
# Pillow actually looks in most of these system font folders by default.
|
||||
font_dirs = [
|
||||
# Windows
|
||||
R"C:\Windows\Fonts",
|
||||
R"C:\WINNT\Fonts",
|
||||
R"%LocalAppData%\Microsoft\Windows\Fonts", # (fonts installed only for the current user)
|
||||
# macOS
|
||||
"/Library/Fonts",
|
||||
"/System/Library/Fonts",
|
||||
"~/Library/Fonts", # (fonts installed only for the current user)
|
||||
# Linux:
|
||||
# "/usr/share/fonts", # handled more generally below:
|
||||
*[data_dir + "/fonts" for data_dir in os.environ.get("XDG_DATA_DIRS", "/usr/share").split(":")],
|
||||
"/usr/local/share/fonts",
|
||||
"~/.fonts", # (fonts installed only for the current user)
|
||||
# Android:
|
||||
"/system/fonts",
|
||||
"/data/fonts",
|
||||
]
|
||||
font_names = [
|
||||
"NotoSansMono",
|
||||
"DejaVuSansMono",
|
||||
"LiberationMono",
|
||||
"UbuntuMono",
|
||||
"Hack",
|
||||
"FiraMono",
|
||||
"Inconsolata",
|
||||
"SourceCodePro",
|
||||
"DroidSansMono",
|
||||
"Consolas",
|
||||
"CourierNew",
|
||||
"LucidaConsole",
|
||||
"Monaco",
|
||||
]
|
||||
font = None
|
||||
for font_dir in font_dirs:
|
||||
path = Path(os.path.expandvars(os.path.expanduser(font_dir)))
|
||||
files = path.glob("**/*.ttf")
|
||||
for file in files:
|
||||
# print(file.stem)
|
||||
if file.stem in font_names:
|
||||
font = ImageFont.truetype(str(file), size=16, layout_engine=ImageFont.LAYOUT_BASIC)
|
||||
break
|
||||
if font:
|
||||
break
|
||||
if not font:
|
||||
print("Font not found, using default (built-in) font.")
|
||||
font = ImageFont.load_default()
|
||||
|
||||
ch_width: int
|
||||
ch_height: int
|
||||
ch_width, ch_height = font.getsize('A') # type: ignore
|
||||
assert isinstance(ch_width, int), "ch_width is not an int, but a " + str(type(ch_width)) # type: ignore
|
||||
assert isinstance(ch_height, int), "ch_height is not an int, but a " + str(type(ch_height)) # type: ignore
|
||||
|
||||
def rasterize(doc: 'AnsiArtDocument') -> Image.Image:
|
||||
# make PIL image
|
||||
img = Image.new('RGB', (doc.width * ch_width, doc.height * ch_height), color='black')
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# draw cell backgrounds
|
||||
for y in range(doc.height):
|
||||
for x in range(doc.width):
|
||||
bg_color = doc.bg[y][x]
|
||||
draw.rectangle((x * ch_width, y * ch_height, (x + 1) * ch_width, (y + 1) * ch_height), fill=bg_color)
|
||||
|
||||
# draw text
|
||||
for y in range(doc.height):
|
||||
for x in range(doc.width):
|
||||
char = doc.ch[y][x]
|
||||
bg_color = doc.bg[y][x]
|
||||
fg_color = doc.fg[y][x]
|
||||
try:
|
||||
draw.text((x * ch_width, y * ch_height), char, font=font, fill=fg_color)
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
return img
|
Loading…
Reference in New Issue
Block a user