support for timg as an alternative to chafa

This commit is contained in:
Lionel Dricot 2022-03-17 10:18:00 +01:00
parent a651537052
commit 435ab36525
3 changed files with 72 additions and 57 deletions

View File

@ -1,14 +1,16 @@
# Offpunk History
## 1.1 - Unreleased
- Perfect rendering of pictures with chafa 1.8+ and compatible terminal
- Perfect rendering of pictures with chafa 1.8+ and compatible terminal (Kitty)
- timg is supported as an alternative to chafa (with a little glitch)
- "cp cache" put the path of the cached content in clipboard
- "cp url X" will copy the URL of link X (suggested by Eoin Carney)
- HTML renderering of <pre> has been improved
- "fold" has been removed as it doesnt work well anyway with our width.
- "fold" has been removed as it doesnt work well and can be replaced with "!fold".
- Improved clipboard URL detection an fixed crash when binary in clipboard
- Fixed crash when chafa is not installed (Thanks Xavier Hinault for the report)
- Fixed crash when python-readability not installed (Thanks Nic for the report)
- Fixed some URL being wronlgy interpreted as IPv6
## 1.0 - March 14th 2022
- Default width is now the standard 72

View File

@ -67,7 +67,7 @@ Announces about Offpunk will be made on Ploums Gemlog => gemini://rawtext.cl
Offpunk has no "strict dependencies", i.e. it should run and work without anything
else beyond the Python standard library and the "less" pager. However, it will "opportunistically
import" a few other libraries if they are available to offer an improved
experience or some other features. Python libraries requests, bs4 and readability are required for http/html support. Images are displayed if python-ansiwrap and chafa are presents (python-pil is needed for chafa version before 1.10).
experience or some other features. Python libraries requests, bs4 and readability are required for http/html support. Images are displayed if python-ansiwrap and chafa or timg are presents (python-pil is needed for chafa version before 1.10). When displaying only a picture (not inline), rendering will be pixel perfect in compatible terminals (such as Kitty) if chafa is at least version 1.8 or if timg is used.
To avoid using unstable or too recent libraries, the rule of thumb is that a library should be packaged in Debian/Ubuntu. Keep in mind that Offpunk is mainly tested will all libraries installed. If you encounter a crash without one optional dependencies, please report it.
@ -86,6 +86,7 @@ Run command `version` in offpunk to see if you are missing some dependencies.
* [Python editor](https://github.com/fmoo/python-editor) is used to edit your lists with "list edit". (apt-get install python3-editor)
* [Xsel](http://www.vergenet.net/~conrad/software/xsel/) allows to `go` to the URL copied in the clipboard without having to paste it (both X and traditional clipboards are supported). Also needed to use the `copy` command. (apt-get install xsel)
* [Chafa](https://hpjansson.org/chafa/) allows to display pictures in your console. Install it and browse to an HTML page with picture to see the magic.
* [Timg](https://github.com/hzeller/timg) is a slower alternative to chafa for inline images. But it has better rendering when displaying only the image. Install both to get the best of both world.
* [Python-pil](http://python-pillow.github.io/) is required to only display the first frame of animated gif with chafa if chafa version is lower than 1.10.
* [Python-setproctitle](https://github.com/dvarrazzo/py-setproctitle) will change the process name from "python" to "offpunk". Useful to kill it without killing every python service.

View File

@ -109,50 +109,73 @@ def wraplines(*args,**kwargs):
def wrapparagraph(*args,**kwargs):
return "\n".join(wraplines(*args,**kwargs))
_HAS_PIL = False
_RENDER_IMAGE = False
_HAS_TIMG = False
#_HAS_TIMG = shutil.which('timg')
if _HAS_TIMG:
chafa_inline = "timg --frames=1 -p q -g %sx1000"
chafa_cmd = "timg --frames=1 -C"
if _HAS_ANSIWRAP:
_RENDER_IMAGE = True
try:
from PIL import Image
_HAS_PIL = True
except ModuleNotFoundError:
_HAS_PIL = False
_HAS_TIMG = shutil.which('timg')
_HAS_CHAFA = shutil.which('chafa')
if not _RENDER_IMAGE:
if _HAS_CHAFA:
# starting with 1.10, chafa can return only one frame
# which allows us to drop dependancy for PIL
return_code = subprocess.run("chafa --version",shell=True, capture_output=True)
output = return_code.stdout.decode()
# with chafa < 1.10, --version was returned to stderr instead of stdout.
if output == '':
_NEW_CHAFA = False
chafa_inline = "chafa --bg white -s %s -w 1 -f symbols"
chafa_cmd = "chafa --bg white -w 1"
else:
_NEW_CHAFA = True
chafa_inline += "--animate=off "
else:
_NEW_CHAFA = False
_NEW_CHAFA = False
if _NEW_CHAFA and _HAS_ANSIWRAP:
_RENDER_IMAGE = True
else:
# All this code to know if we render image inline or not
if _HAS_CHAFA:
# starting with 1.10, chafa can return only one frame
# which allows us to drop dependancy for PIL
return_code = subprocess.run("chafa --version",shell=True, capture_output=True)
output = return_code.stdout.decode()
# with chafa < 1.10, --version was returned to stderr instead of stdout.
if output != '':
_NEW_CHAFA = True
if _NEW_CHAFA and _HAS_ANSIWRAP:
_RENDER_IMAGE = True
elif _HAS_TIMG and _HAS_ANSIWRAP:
_RENDER_IMAGE = True
elif _HAS_CHAFA and _HAS_PIL and _HAS_ANSIWRAP:
_RENDER_IMAGE = True
else:
_RENDER_IMAGE = False
print("To render images inline, you need either chafa or timg and ansiwrap.")
if not _NEW_CHAFA and not _HAS_TIMG:
print("Before Chafa 1.10, you also need python-pil")
#return ANSItext that can be show by less
def inline_image(img_file,width):
#Chafa is faster than timg inline. Let use that one by default
inline = None
ansi_img = ""
if _HAS_CHAFA and _HAS_ANSIWRAP:
if _HAS_PIL and not _NEW_CHAFA:
# this code is a hack to remove frames from animated gif
img_obj = Image.open(img_file)
if hasattr(img_obj,"n_frames") and img_obj.n_frames > 1:
# we remove all frames but the first one
img_obj.save(img_file,save_all=False)
inline = "chafa --bg white -s %s -w 1 -f symbols"
elif _NEW_CHAFA:
inline = "chafa --bg white -s %s -w 1 -f symbols --animate=off"
if not inline and _HAS_TIMG and _HAS_ANSIWRAP:
inline = "timg --frames=1 -p q -g %sx1000"
if inline:
cmd = inline%width+ " \"%s\""%img_file
try:
from PIL import Image
_HAS_PIL = True
if _HAS_ANSIWRAP and _HAS_CHAFA:
_RENDER_IMAGE = True
else:
print("chafa and ansiwrap are required to render images in terminal")
_RENDER_IMAGE = False
except ModuleNotFoundError:
print("python-pil, chafa and ansiwrap are required to render images")
_RENDER_IMAGE = False
_HAS_PIL = False
return_code = subprocess.run(cmd,shell=True, capture_output=True)
ansi_img = return_code.stdout.decode()
except Exception as err:
ansi_img = "***image failed : %s***\n" %err
return ansi_img
def terminal_image(img_file):
#Render by timg is better than old chafa.
# it is also centered
cmd = None
if _HAS_TIMG:
cmd = "timg --frames=1 -C"
elif _HAS_CHAFA:
cmd = "chafa --bg white -w 1"
if cmd:
cmd = cmd + " \"%s\""%img_file
subprocess.run(cmd,shell=True)
_HAS_XSEL = shutil.which('xsel')
@ -741,17 +764,7 @@ class ImageRenderer(AbstractRenderer):
spaces = 0
else:
spaces = int((term_width() - width)//2)
try:
if _HAS_PIL:
img_obj = Image.open(img)
if hasattr(img_obj,"n_frames") and img_obj.n_frames > 1:
# we remove all frames but the first one
img_obj.save(img,save_all=False)
cmd = chafa_inline%width+ " \"%s\""%img
return_code = subprocess.run(cmd,shell=True, capture_output=True)
ansi_img = return_code.stdout.decode()
except Exception as err:
ansi_img = "***image failed : %s***\n" %err
ansi_img = inline_image(img,width)
#Now centering the image
lines = ansi_img.splitlines()
new_img = ""
@ -761,8 +774,7 @@ class ImageRenderer(AbstractRenderer):
def display(self,mode=None,title=None):
if title:
print(title)
cmd = chafa_cmd + " \"%s\""%self.body
subprocess.run(cmd,shell=True)
terminal_image(self.body)
return True
class HtmlRenderer(AbstractRenderer):