diff --git a/CHANGELOG b/CHANGELOG index fb31609..dfe3876 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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
 has been improved
-- "fold" has been removed as it doesn’t work well anyway with our width.
+- "fold" has been removed as it doesn’t 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
diff --git a/README.md b/README.md
index 1db6dc7..dd1c3a5 100644
--- a/README.md
+++ b/README.md
@@ -67,7 +67,7 @@ Announces about Offpunk will be made on Ploum’s 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.
 
diff --git a/offpunk.py b/offpunk.py
index b3f5059..4f274b8 100755
--- a/offpunk.py
+++ b/offpunk.py
@@ -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 ANSI text 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):