{"id":21690007,"url":"https://github.com/poly2it/sixels-py","last_synced_at":"2026-05-18T08:06:16.744Z","repository":{"id":200319805,"uuid":"657634948","full_name":"poly2it/sixels-py","owner":"poly2it","description":"A sixel renderer as well as documentation of the sixel format.","archived":false,"fork":false,"pushed_at":"2023-11-03T14:03:34.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-20T12:54:55.166Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/poly2it.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-23T13:44:01.000Z","updated_at":"2023-06-23T13:50:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"85699ef3-bda4-4da7-b9cf-bca1fa3ffdd0","html_url":"https://github.com/poly2it/sixels-py","commit_stats":null,"previous_names":["poly2it/sixels-py"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/poly2it/sixels-py","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poly2it%2Fsixels-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poly2it%2Fsixels-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poly2it%2Fsixels-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poly2it%2Fsixels-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/poly2it","download_url":"https://codeload.github.com/poly2it/sixels-py/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/poly2it%2Fsixels-py/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33170447,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T05:43:36.989Z","status":"ssl_error","status_checked_at":"2026-05-18T05:43:19.133Z","response_time":71,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-25T17:28:31.527Z","updated_at":"2026-05-18T08:06:16.711Z","avatar_url":"https://github.com/poly2it.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sixels-Py\nThis is my attempt at writing an efficient [sixel](https://en.wikipedia.org/wiki/Sixel) encoder in Python. It is fairly lightweight, and uses only PIL as a dependency.\n\n![](docs/screenshot.png)\n\n## Sixel format\nDuring development of this project, I found myself increasinly frustrated by the lack of comprehendable documentation for the format. The format in of itself is quite simple, but it's easy to get lost at specifics, like transparency.\n\n\n\u003cimg style=\"image-rendering: pixelated;\" src=\"docs/example_sixel-96x.png\"\u003e  \n\n```\n\\x1bPq1;1;\"1;1;12;12$\n#0;2;92;95;100#1;2;0;0;0\n#0~~pp^nr~pp~~$#1??MM_OK?MM??-\n#0~~zveddfvz~~$#1??CGXYYWGC??-\n\\x1b\\\\\n```\n*the sixel format doesn't use newlines, they are here for readability*\n\nLine one contains the escape code for initialising a sixel, `\\x1bPq`. The data following are the parameters for the sixel. [Black Box](https://gitlab.gnome.org/raggesilver/blackbox), the emulator I am using, doesn't seem to care too much at all about these parameters. Anyway, the format is as following:\n\n- P1:  \nThe P1 (`1;`) parameter was used to control the aspect ratio of rendered pixels. It has been deprecated long since, and doesn't serve a function today. The possible values, specifying width:height are as follows:\n\n|  **Value**  |  **Aspect Ratio**  |\n:------------:|:------------------:|\n|  None       |  2:1               |\n|  0, 1       |  2:1               | \n|  2          |  5:1               |\n|  3, 4       |  3:1               |\n|  5, 6       |  2:1               |\n|  7, 8, 9    |  1:1               |\n\n- P2  \nThe P2 (`1;`) parameter decides if the renderer should interpret the first palette index as a transparent color or not. My program achives transparency simply by not appending data for any colour for transparent pixels, but I am sceptical as to whether or not this is specification compliant. If set to 0 or 2, the first palette colour will be interpreted as a reference to the background of the terminal. If set to 1, the palette index will be interpreted as is.\n\n- Raster attributes  \n`\"1;1;12;12` is a control function to overwrite the aspect ratio defined in P1. The format is `\"{pixel_height}:{pixel_width};{image_height};{image_width}`. You are supposed to be able to change the aspect ratio of a rendered pixel with this. The reason for the existance of the last two parameters is unclear. The original documentation itself states that the sixel data width and height should overwrite this parameter. The VT300 interpreted a 0 or 2 in P2 as a setting to enable background discarding.\n\nAt the end of the parameters, we append a `$`. This means overdraw and is used in the data section. \n\nLine two contains the palette colour definitions for the sixel. It's a string of reference numbers which the sixel data string uses to enable coloured rendering. Let's focus on a single palette item, they are all of the same structure. `#0;2;92;95;100`, by `#0;`, defines our 0th palette colour. The index is followed by a `2;`. This sets the colour mode to RGB, the way in which the following last three parameters should be interpreted. Another available colour mode is HSL, but I haven't used it personally, neither have I seen anyone else use it. Lastly, the palette item sets the actual colour using `92;95;100`. Please note that these colours are specified in red, green and blue, ranging between 0 and 100, as opposed to the standard today, 0 to 255. To add more palette items, just follow the preceeding item with a new index. Do **not** separate the palette items with semicolons. Example: `#0;2;92;95;100#1;2;0;0;0`. You can have a maximum of 256 (0 to 255) palette colours.\n\nLine three and four contains the data section of the sixel image. First we start by selecting a colour to draw with, `#0`. Then we append bit data encoded in ascii, each character of which being associated with 1 horizontal and 6 vertical pixels on screen. The ascii corresponds to six bits. The least significant bit is rendered at the top of the sixel. In an example, `000101` would render a column filled at the top pixel, followed by a gap of one pixel, a last pixel and then a blank space for three pixels at the bottom. We can encode this to an ascii symbol by appending the decimal number 63 to the binary number, then getting the corresponding ascii symbol of that index. The first coloured row continues like this with the symbols `~~pp^nr~pp~~`, before we run into a `$`. As you might have read above, this symbol instructs the renderer to overdraw on the line which we are currently drawing. This allows to render as many colours as we want from our palette onto a single row. We continue with `#1??MM_OK?MM??`, before finally terminating this row with a `-`. This hyphen instructs the renderer that we are done with the line, and that want to move on to the next row of six pixels in height. The row following is in the same pattern as the first one.\n\nWhile my renderer doesn't implement it for performance reasons, the sixel format also supports [run-length encoding](https://en.wikipedia.org/wiki/Run-length_encoding). To use RLE, concatenate equal bit representators to a single ascii letter, followed by an `!` and the original number of equal symbols in the sequence, like this: `O!14`.\n\nOn line five, we terminate the sixel using the `\\x1b\\\\` sequence. \n\n### Further reading\nhttps://vt100.net/docs/vt3xx-gp/chapter14.html  \nhttps://en.wikipedia.org/wiki/Sixel\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoly2it%2Fsixels-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpoly2it%2Fsixels-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoly2it%2Fsixels-py/lists"}