GithubHelp home page GithubHelp logo

SIXEL support about tuifimanager HOT 6 OPEN

GiorgosXou avatar GiorgosXou commented on June 14, 2024 1
SIXEL support

from tuifimanager.

Comments (6)

GiorgosXou avatar GiorgosXou commented on June 14, 2024 2

👁️ Preview

Nice... we have some progress. After some intense pitfalls, research, trial and error, I finally figured out how to print actual sixels inside ncurses, without uberzug.

tuifi_original_sixel_test_Peek 2024-03-24 16-31

(Preview Might seem as a joke, but (just so you know) it is a huge progress!)

👨‍💻 Code

Here's how i managed to do so:

Click to expand
from io import StringIO
import unicurses as uc
from PIL import Image



class SixelConverter: # https://github.com/lubosz/python-sixel

    def __init__(self, f8bit=False, ncolor=256):

        self._slots = [0] * 257
        self._ncolor = ncolor

        if f8bit:  # 8bit mode
            self.DCS = '\x90'
            self.ST = '\x9c'
        else:
            self.DCS = '\x1bP'
            self.ST = '\x1b\\'


    def __write_header(self):
        # start Device Control String (DCS)
        uc.putp(self.DCS)

        # write header
        aspect_ratio = 7  # means 1:1
        background_option = 0
        # background_option = 1
        dpi = 75  # dummy value
        template = '%d;%d;%dq"1;1;%d;%d'
        args = (aspect_ratio, background_option, dpi, self.width, self.height)
        uc.putp(template % args)

        
    def __write_palette_section(self):

        palette = self.palette

        # write palette section
        for i in range(0, self._ncolor * 3, 3):
            no = i / 3
            r = palette[i + 0] * 100 / 256
            g = palette[i + 1] * 100 / 256
            b = palette[i + 2] * 100 / 256
            uc.putp('#%d;2;%d;%d;%d' % (no, r, g, b))


    def __write_body_without_alpha_threshold_fast(self, data ):
        height = self.height
        width = self.width
        n = 1
        for y in range(0, height):
            p = y * width
            cached_no = data[p]
            count = 1
            c = -1
            for x in range(0, width):
                color_no = data[p + x]
                if color_no == cached_no:  # and count < 255:
                    count += 1
                else:
                    if cached_no == -1 :
                        c = 0x3f
                    else:
                        c = 0x3f + n
                        if self._slots[cached_no] == 0:
                            palette = self.palette
                            r = palette[cached_no * 3 + 0] * 100 / 256
                            g = palette[cached_no * 3 + 1] * 100 / 256
                            b = palette[cached_no * 3 + 2] * 100 / 256
                            self._slots[cached_no] = 1
                            uc.putp('#%d;2;%d;%d;%d' % (cached_no, r, g, b))
                        uc.putp('#%d' % cached_no)
                    if count < 3:
                        uc.putp(chr(c) * count)
                    else:
                        uc.putp('!%d%c' % (count, c))
                    count = 1
                    cached_no = color_no
            if c != -1 and count > 1:
                if cached_no == -1 :
                    c = 0x3f
                else:
                    if self._slots[cached_no] == 0:
                        palette = self.palette
                        r = palette[cached_no * 3 + 0] * 100 / 256
                        g = palette[cached_no * 3 + 1] * 100 / 256
                        b = palette[cached_no * 3 + 2] * 100 / 256
                        self._slots[cached_no] = 1
                        uc.putp('#%d;2;%d;%d;%d' % (cached_no, r, g, b))
                    uc.putp('#%d' % cached_no)
                if count < 3:
                    uc.putp(chr(c) * count)
                else:
                    uc.putp('!%d%c' % (count, c))
            if n == 32:
                n = 1
                uc.putp('-')  # write sixel line separator
            else:
                n <<= 1
                uc.putp('$')  # write line terminator


    def __write_body_section(self):
        data = self.data
        self.__write_body_without_alpha_threshold_fast(data)


    def __write_terminator(self):
        # write ST
        uc.putp(self.ST)  # terminate Device Control String


    def getvalue(self):
        output = StringIO()

        try:
            self.write(output)
            value = output.getvalue()

        finally:
            output.close()

        return value


    def write(self, file, w=None, h=None,):
        self._slots = [0] * 257
        image = Image.open(file)
        image = image.convert("RGBA" if image.format == "PNG" else "RGB").convert("P",
                                             palette=Image.Palette.ADAPTIVE,
                                             colors=self._ncolor)
        if w or h:
            width, height = image.size
            if not w:
                w = width
            if not h:
                h = height
            image = image.resize((w, h))


        self.palette = image.getpalette()
        self.data = image.getdata()
        self.width, self.height = image.size
        self.__write_header()
        self.__write_body_section()
        self.__write_terminator()
        uc.putp('\n')



stdscr = uc.initscr()              # Global UniCurses Variable
event  = -1

uc.start_color  ( )
uc.cbreak       ( )
uc.noecho       ( )
uc.curs_set     (0)
uc.mouseinterval(0)                 # Initializing Mouse and then Update/refresh() stdscr
uc.mousemask    (uc.ALL_MOUSE_EVENTS | uc.REPORT_MOUSE_POSITION) # print("\033[?1003h\n")
uc.keypad       (stdscr, True )
uc.nodelay      (stdscr, False)
uc.raw()

uc.move(3,7)
uc.refresh      ( )

HEIGHT,WIDTH = uc.getmaxyx(stdscr)
c = SixelConverter()
i = 1

while event != 27 : # Main loop 
    event = uc.get_wch()
    if event == uc.KEY_MOUSE: 
        uc.clear()
        continue

    uc.lib1.mvcur(HEIGHT-1, WIDTH-1, 5,i) 
    c.write("/home/xou/Downloads/me.png", h=96,w=96)
    i+=1

    if event == uc.CCHAR('a'):
        uc.mvaddstr(i,10, 'adfabfea')

    # uc.lib2.puts(uc.CSTR("\x1bPq#0;2;0;0;0#1;2;100;100;0#2;2;0;100;0#1~~@@vv@@~~@@~~$#2??}}GG}}??}}??-#1!14@\x1b\\" ))

    uc.refresh()

    if event == uc.KEY_RESIZE:
        uc.resize_term(0,0)
uc.endwin()

# # print("\x1bPq#0;2;0;0;0#1;2;100;100;0#2;2;0;100;0#1~~@@vv@@~~@@~~$#2??}}GG}}??}}??-#1!14@\x1b\\")
# c = SixelConverter()
# c.write("/home/xou/Downloads/me.png", h=160,w=160)
# c.write("/home/xou/Downloads/image.jpg", h=160,w=560)
# c.write("/home/xou/Downloads/Afisa.jpg", h=60,w=150)

🌐 Research

Sixel and curses related subjects related to:

from tuifimanager.

GiorgosXou avatar GiorgosXou commented on June 14, 2024 1

Proof of concept

Don't get too excited, I don't have a lot of free time to work on it (money would help)
sixel_proof_of_concept_Peek 2023-09-18 16-01

from tuifimanager.

GiorgosXou avatar GiorgosXou commented on June 14, 2024

Actually I should use uberzug++

from tuifimanager.

GiorgosXou avatar GiorgosXou commented on June 14, 2024

You know what... I want to stay original, so... I replaced alacritty with alacritty-sixel-branch and I'll start expirimenting with real sixels instead of trying the work-around uberzug method.

from tuifimanager.

GiorgosXou avatar GiorgosXou commented on June 14, 2024

it works as expected on alacritty-sixel-branch and wezterm but not on xterm for some reason (under ncurses)

from tuifimanager.

GiorgosXou avatar GiorgosXou commented on June 14, 2024

Ok it actually works just fine with xterm -ti vt340. also this video

from tuifimanager.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.