Skip to content

Instantly share code, notes, and snippets.

@olofsen
Last active May 31, 2020 06:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olofsen/9057600 to your computer and use it in GitHub Desktop.
Save olofsen/9057600 to your computer and use it in GitHub Desktop.
Reading, displaying, and converting a Sixel Graphics file with Julia
# 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