Add GIMP palettes support, refactoring

You can now use GIMP palette file as a colormap, by using its filename as a color.
Add the well known Matlab jet72 palette (jet72.gpl).

Group functions in sections.
This commit is contained in:
Johann Dreo 2013-05-26 16:07:38 +02:00
commit 3f59b8c31f
2 changed files with 177 additions and 31 deletions

View file

@ -13,9 +13,50 @@ import glob
import math
import importlib
###########
# Library #
###########
###############################################################################
# Ressource parsing helpers
###############################################################################
def parse_gimp_palette( filename ):
"""
Parse the given filename as a GIMP palette (.gpl)
Return the filename (without path and extension) and a list of ordered
colors.
Generally, the colors are RGB triplets, thus this function returns:
(name, [ [R0,G0,B0], [R1,G1,B1], ... , [RN,GN,BN] ])
"""
fd = open(filename)
# remove path and extension, only keep the file name itself
name = os.path.splitext( os.path.basename(filename ))[0]
# The first .gpl line is a header
assert( fd.readline().strip() == "GIMP Palette" )
# Then the full name of the palette
long_name = fd.readline().strip()
# Then the columns number.
# split on colon, take the second argument as an int
columns = int( fd.readline().strip().split(":")[1].strip() )
# Then the colors themselves.
palette = []
for line in fd:
# skip lines with only a comment
if re.match("^\s*#.*$", line ):
continue
# decode the columns-ths codes. Generally [R G B] followed by a comment
colors = [ int(c) for c in line.split()[:columns] ]
palette.append( colors )
return name,palette
###############################################################################
# Global variables
###############################################################################
# Available styles
styles = {
@ -30,37 +71,6 @@ colors = {
"magenta": 5, "cyan": 6, "white": 7, "none": -1
}
ansi_min = 16
ansi_max = 232
def rgb_rainbow( x, freq = 1.0/(256.0/math.pi) ):
scope = (ansi_max - ansi_min)/2.0
red = ansi_min + scope * (1+math.sin( 2*freq*x + math.pi/2 ))
green = ansi_min + scope * (1+math.sin( 2*freq*x - math.pi/2 ))
blue = ansi_min + scope * (1+math.sin( freq*x - math.pi/2 ))
return ( red, green, blue )
def rgb_to_ansi( red, green, blue ):
offset = 42.5
is_gray = True
while is_gray:
if red < offset or green < offset or blue < offset:
all_gray = red < offset and green < offset and blue < offset
is_gray = False
offset += 42.5
if all_gray:
val = ansi_max + round( (red + green + blue)/33.0 )
return int(val)
else:
val = ansi_min
for color,modulo in zip( [red, green, blue], [6*6, 6, 1] ):
val += round(6.0 * (color / 256.0)) * modulo
return int(val)
rainbow = ["magenta", "blue", "cyan", "green", "yellow", "red"]
colormap = rainbow # default colormap to rainbow
colormap_idx = 0
@ -70,15 +80,40 @@ scale = (0,100)
# Escaped end markers for given color modes
endmarks = {8: ";", 256: ";38;5;"}
ansi_min = 16
ansi_max = 232
def rgb_rainbow( x, freq = 1.0/(256.0/math.pi) ):
"""Analytical expression of a n-colors rainbow colormap"""
scope = (ansi_max - ansi_min)/2.0
red = ansi_min + scope * (1+math.sin( 2*freq*x + math.pi/2 ))
green = ansi_min + scope * (1+math.sin( 2*freq*x - math.pi/2 ))
blue = ansi_min + scope * (1+math.sin( freq*x - math.pi/2 ))
return ( red, green, blue )
###############################################################################
# Load available extern ressources
###############################################################################
# load available themes
themes = {}
themes_dir=os.path.dirname(os.path.realpath(__file__))
os.chdir( themes_dir )
for f in glob.iglob("colout_*.py"):
module = ".".join(f.split(".")[:-1]) # remove extension
name = "_".join(module.split("_")[1:]) # remove the prefix
themes[name] = importlib.import_module(module)
# load available colormaps (GIMP palettes format)
colormaps = {}
for p in glob.iglob("*.gpl"):
name,palette = parse_gimp_palette(p)
if name in colormaps:
raise Exception('Duplicated palette filename: %s' % name)
colormaps[name] = palette
# load available pygments lexers
lexers = []
try:
@ -98,6 +133,30 @@ else:
lexers.sort()
###############################################################################
# Library
###############################################################################
def rgb_to_ansi( red, green, blue ):
"""Convert a RGB color to its closest 256-colors ANSI index"""
offset = 42.5
is_gray = True
while is_gray:
if red < offset or green < offset or blue < offset:
all_gray = red < offset and green < offset and blue < offset
is_gray = False
offset += 42.5
if all_gray:
val = ansi_max + round( (red + green + blue)/33.0 )
return int(val)
else:
val = ansi_min
for color,modulo in zip( [red, green, blue], [6*6, 6, 1] ):
val += round(6.0 * (color / 256.0)) * modulo
return int(val)
def colorin(text, color="red", style="normal"):
"""
Return the given text, surrounded by the given color ASCII markers.
@ -162,6 +221,16 @@ def colorin(text, color="red", style="normal"):
else:
colormap_idx = 0
elif color in colormaps.keys():
mode = 256
color_nb = rgb_to_ansi( *colormaps[color][colormap_idx] )
color_code = str( color_nb )
if colormap_idx < len(colormaps[color]):
colormap_idx += 1
else:
colormap_idx = 0
elif color == "scale":
try:
import babel.numbers as bn

77
colout/jet72.gpl Normal file
View file

@ -0,0 +1,77 @@
GIMP Palette
Name: MATLAB Jet (72)
Columns: 3
#
0 0 127 0
0 0 127 #1
0 0 141 #2
0 0 155 #3
0 0 169 #4
0 0 183 #5
0 0 198 #6
0 0 212 #7
0 0 226 #8
0 0 240 #9
0 0 255 #10
0 14 255 #11
0 28 255 #12
0 42 255 #13
0 56 255 #14
0 70 255 #15
0 84 255 #16
0 98 255 #17
0 112 255 #18
0 127 255 #19
0 141 255 #20
0 155 255 #21
0 169 255 #22
0 183 255 #23
0 198 255 #24
0 212 255 #25
0 226 255 #26
0 240 255 #27
0 255 255 #28
14 255 240 #29
28 255 226 #30
42 255 212 #31
56 255 198 #32
70 255 183 #33
84 255 169 #34
98 255 155 #35
112 255 141 #36
127 255 127 #37
141 255 112 #38
155 255 98 #39
169 255 84 #40
183 255 70 #41
198 255 56 #42
212 255 42 #43
226 255 28 #44
240 255 14 #45
255 255 0 #46
255 240 0 #47
255 226 0 #48
255 212 0 #49
255 198 0 #50
255 183 0 #51
255 169 0 #52
255 155 0 #53
255 141 0 #54
255 127 0 #55
255 112 0 #56
255 98 0 #57
255 84 0 #58
255 70 0 #59
255 56 0 #60
255 42 0 #61
255 28 0 #62
255 14 0 #63
255 0 0 #64
240 0 0 #65
226 0 0 #66
212 0 0 #67
198 0 0 #68
183 0 0 #69
169 0 0 #70
155 0 0 #71
141 0 0 #72