Last active
May 31, 2020 06:15
-
-
Save olofsen/9057600 to your computer and use it in GitHub Desktop.
Reading, displaying, and converting a Sixel Graphics file with Julia
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The function ds() below reads a Sixel graphics file and creates an RGB Image, | |
# which can then be displayed and processed using the Image package. | |
# Public domain example code. | |
using Color, Images, ImageView | |
function vt340_palette() | |
pal = RGB[] | |
push!(pal, RGB(0.00, 0.00, 0.00)) | |
push!(pal, RGB(0.20, 0.20, 0.80)) | |
push!(pal, RGB(0.80, 0.13, 0.13)) | |
push!(pal, RGB(0.20, 0.80, 0.20)) | |
push!(pal, RGB(0.80, 0.20, 0.80)) | |
push!(pal, RGB(0.20, 0.80, 0.80)) | |
push!(pal, RGB(0.80, 0.80, 0.20)) | |
push!(pal, RGB(0.53, 0.53, 0.53)) | |
push!(pal, RGB(0.26, 0.26, 0.26)) | |
push!(pal, RGB(0.33, 0.33, 0.60)) | |
push!(pal, RGB(0.60, 0.26, 0.26)) | |
push!(pal, RGB(0.33, 0.60, 0.33)) | |
push!(pal, RGB(0.60, 0.33, 0.60)) | |
push!(pal, RGB(0.33, 0.60, 0.60)) | |
push!(pal, RGB(0.60, 0.60, 0.33)) | |
push!(pal, RGB(0.80, 0.80, 0.80)) | |
pal | |
end | |
type SixelFile | |
s::Array{Uint8} | |
nc::Int | |
lc::Int | |
bc::Int | |
ip::Int | |
cp::Int | |
c::Char | |
hd::Bool | |
err::Bool | |
pars::Array{Int} | |
function SixelFile() | |
new(zeros(Uint8,0), 0, 0, 0, 0, 1, '\0', false, false, zeros(Int,7)) | |
end | |
end | |
function readSixels(sf::SixelFile, filnam::String) | |
f = open(filnam,"r") | |
sf.s = read(f,Uint8,filesize(filnam)); | |
sf.nc = length(sf.s) | |
close(f) | |
end | |
function sixel(sf::SixelFile) | |
while true | |
sf.ip += 1 | |
if sf.ip>sf.nc; sf.err=true; return; end | |
sf.c = sf.s[sf.ip] | |
if sf.c=='\e' || sf.c>' '; break; end | |
end | |
end | |
function number(sf::SixelFile) | |
k = 0 | |
while true | |
sixel(sf) | |
if sf.err; return -1; end | |
if sf.c<'0' || sf.c>'9'; return k; end | |
k = k*10 + (int(sf.c)-int('0')); | |
end | |
end | |
function header(sf::SixelFile) | |
if sf.c=='\e' | |
sixel(sf) | |
if sf.c!='P'; return; end | |
end | |
ip = 0 | |
while true | |
n = number(sf) | |
if sf.err; return; end | |
if sf.c=='q'; break; end | |
ip += 1 | |
sf.pars[ip] = n | |
end | |
sixel(sf) | |
if sf.err; return; end | |
if sf.c=='"' | |
ip = 3 | |
while true | |
n = number(sf) | |
if n<0; break; end | |
ip += 1 | |
sf.pars[ip] = n | |
if sf.c!=';'; break; end | |
end | |
end | |
sf.hd = true | |
end | |
function color(sf::SixelFile) | |
k = number(sf) | |
k = rem(k,16) | |
sf.cp = k+1 | |
if sf.c!=';'; return; end | |
d = number(sf) | |
if sf.c!=';'; return; end | |
r = number(sf) | |
if sf.c!=';'; return; end | |
g = number(sf) | |
if sf.c!=';'; return; end | |
b = number(sf) | |
end | |
function color(sf::SixelFile, p::Array) | |
k = number(sf) | |
k = rem(k,16) | |
sf.cp = k+1 | |
if sf.c!=';'; return; end | |
d = number(sf) | |
if sf.c!=';'; return; end | |
r = number(sf) | |
if sf.c!=';'; return; end | |
g = number(sf) | |
if sf.c!=';'; return; end | |
b = number(sf) | |
if d==1 | |
p[sf.cp] = convert(RGB, HSL((r+240)%360, b/100, g/100)) | |
elseif d==2 | |
p[sf.cp] = RGB(r/100,g/100,b/100) | |
end | |
end | |
function getcolor(cp, p::Array{RGB,1}) | |
[iround(p[cp].r*255), iround(p[cp].g*255), iround(p[cp].b*255)] | |
end | |
function clear(sf::SixelFile, img::Image, col::Array) | |
for j=1:size(img.data,3), i=1:size(img.data,2) | |
img[:,i,j] = col | |
end | |
end | |
# get dimensions and colors | |
function pass1(sf::SixelFile, p::Array{RGB,1}) | |
sf.lc = 0 | |
sf.bc = 0 | |
sf.ip = 0 | |
sf.hd = false | |
sf.err = false | |
bc = 0 | |
sixel(sf) | |
while !sf.err | |
c = sf.c | |
if c=='\e' || c=='\u90' || c=='\u9c' | |
if sf.hd; break; end | |
header(sf) | |
c = sf.c | |
end | |
if !sf.hd; sixel(sf); continue; end | |
if c=='$' | |
if bc>sf.bc; sf.bc=bc; end | |
bc = 0 | |
sixel(sf) | |
elseif c=='-' | |
if bc>sf.bc; sf.bc=bc; end | |
sf.lc += 1 | |
bc = 0 | |
sixel(sf) | |
elseif c=='#' | |
color(sf,p) | |
elseif c=='!' | |
k = number(sf) | |
bc += k | |
sixel(sf) | |
else | |
bc += 1 | |
sixel(sf) | |
end | |
end | |
end | |
function putsixel(sf::SixelFile, img::Image, col::Array, lc::Int, bc::Int, k::Int) | |
msk::Uint8 | |
ic::Uint8 | |
msk = 0x01 | |
ic = int(sf.c)-63 | |
xs = size(img.data,2) | |
ys = size(img.data,3) | |
for j=1:6 | |
if ic&msk>0 | |
for i=1:k | |
x = bc+i | |
y = lc*6+j | |
if x<=xs && y<=ys; img[:,x,y] = col; end | |
end | |
end | |
msk <<= 1 | |
end | |
end | |
# put the sixels in the image | |
function pass2(sf::SixelFile, img::Image, p::Array) | |
bc::Int | |
lc::Int | |
bc = 0 | |
lc = 0 | |
sf.ip = 0 | |
sf.hd = false | |
sf.err = false | |
col = getcolor(1,p) | |
sixel(sf) | |
while !sf.err | |
c = sf.c | |
if c=='\e' || c=='\u90' || c=='\u9c' | |
if sf.hd; break; end | |
header(sf) | |
c = sf.c | |
end | |
if !sf.hd; sixel(sf); continue; end | |
if c=='$' | |
bc = 0 | |
sixel(sf) | |
elseif c=='-' | |
lc += 1 | |
bc = 0 | |
sixel(sf) | |
elseif c=='#' | |
color(sf) | |
col = getcolor(sf.cp, p) | |
elseif c=='!' | |
k = number(sf) | |
putsixel(sf, img, col, lc, bc, k) | |
bc += k | |
sixel(sf) | |
else | |
putsixel(sf, img, col, lc, bc, 1) | |
bc += 1 | |
sixel(sf) | |
end | |
end | |
end | |
function ds(filnam::String, bg::Int=0) | |
sf = SixelFile() | |
readSixels(sf, filnam) | |
p = vt340_palette() | |
pass1(sf,p) | |
if sf.err; return sf; end | |
if sf.pars[6]>0; xs = sf.pars[6]; else; xs = sf.bc; end | |
if sf.pars[7]>0; ys = sf.pars[7]; else; ys = sf.lc*6; end | |
img = Image(Array(Uint8,3,xs,ys), | |
["limits"=>(0x00,0xff), | |
"colordim"=>1, | |
"spatialorder"=>["x","y"], | |
"colorspace"=>"RGB"]) | |
if bg==0 | |
clear(sf, img, getcolor(1,p)) | |
elseif bg==1 | |
clear(sf, img, [0, 0, 0]) | |
elseif bg==2 | |
clear(sf, img, [0xff, 0xff, 0xff]) | |
end | |
pass2(sf, img, p) | |
display(img) | |
img | |
end | |
# img = ds("") | |
# imwrite(img,"") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment