The convertor now converts to gimp, scribus and (enhanced) create draft
palettes.
Converting from Lab requires LittleCMS (and the python bindings).
My additions to the draft are:
- metadata (should be corrected by someone who knows more about xml)
- display informations (columns,rows,line breaks). In inverted ACF/BCF
values as it's the only one that scrolls horizontally.
- color groups (Adobe Swatch Exchange format feature).
- "preferredmodel" tag as you can find in ACF/BCF and Quark swatches
- "spot" attribute
I took the option of choosing '6CLR' for hexachrome values as it wasn't
in the draft and it is the ICC and CGATS key. But it's maybe useless
since I don't know any free software that could deal with these data...
I changed "g" to "k" in the "Gray" model.
I still advocate the optionality of the color space: in palettes like
that one <http://html-color-codes.com/>, it's obvious that the RGB
values are chosen for themselves and not for the color they represent.
It is as useful with any rgb space. It helps you to have an idea of the
entire field of possible colors with your computer's screen. If you
"color manage" that palette, it looses any interest... Don't forget that
many non-professional users won't ever publish their work and don't care
about other user's screens...
PS: There were some mistakes in the Corel color models. 12 is Lab and
not CMYK and RGB is actually coded BGR. And I'm not sure at all the
first color model in the BCF format is XYZ... By the way, if someone
knows how to decrypt AutoCAD's RGB8Encrypt values, I'm interested ;-)
#!/usr/bin/python
# coding: utf-8
#
# swatch_convertor.py â version 2008-04-19
#
# Copyright 2008 Olivier Berten <[EMAIL PROTECTED]>
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
# Output values
# RGB,HSV,HLS,CMY,CMYK,6CLR,YIQ: 0 -> 1
# Lab: L 0 -> 100 | ab -125 -> 125
# XYZ: 0 -> ~100 (cfr. ref)
#
from __future__ import division
import sys
import struct
from collections import defaultdict
import os.path
from xml.etree import ElementTree as etree
from lcms import *
def Lab2RGB8(L,a,b):
Lab = cmsCIELab(L,a,b)
RGB = COLORB()
hLab = cmsCreateLabProfile(None)
hsRGB = cmsCreate_sRGBProfile()
xform = cmsCreateTransform(hLab, TYPE_Lab_DBL, hsRGB, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOTPRECALC)
cmsDoTransform(xform, Lab, RGB, 1)
cmsDeleteTransform(xform)
cmsCloseProfile(hsRGB)
cmsCloseProfile(hLab)
return (RGB[0],RGB[1],RGB[2])
#
# color model conversion formulas: http://www.easyrgb.com/math.php
#
def HSL2RGB(H,S,L):
if ( S == 0 ):
R = L
G = L
B = L
else:
if ( L < 0.5 ):
var_2 = L * ( 1 + S )
else:
var_2 = ( L + S ) - ( S * L )
var_1 = 2 * L - var_2
R = Hue_2_RGB( var_1, var_2, H + ( 1 / 3 ) )
G = Hue_2_RGB( var_1, var_2, H )
B = Hue_2_RGB( var_1, var_2, H - ( 1 / 3 ) )
return (R,G,B)
def Hue_2_RGB( v1, v2, vH ):
if ( vH < 0 ):
vH = vH+1
if ( vH > 1 ):
vH = vH-1
if ( ( 6 * vH ) < 1 ):
return ( v1 + ( v2 - v1 ) * 6 * vH )
if ( ( 2 * vH ) < 1 ):
return ( v2 )
if ( ( 3 * vH ) < 2 ):
return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 )
return ( v1 )
def HSV2RGB(H,S,V):
if ( S == 0 ):
R = V
G = V
B = V
else:
var_h = H * 6
if ( var_h == 6 ):
var_h = 0
var_i = int( var_h )
var_1 = V * ( 1 - S )
var_2 = V * ( 1 - S * ( var_h - var_i ) )
var_3 = V * ( 1 - S * ( 1 - ( var_h - var_i ) ) )
if ( var_i == 0 ):
R = V
G = var_3
B = var_1
elif ( var_i == 1 ):
R = var_2
G = V
B = var_1
elif ( var_i == 2 ):
R = var_1
G = V
B = var_3
elif ( var_i == 3 ):
R = var_1
G = var_2
B = V
elif ( var_i == 4 ):
R = var_3
G = var_1
B = V
else:
R = V
G = var_1
B = var_2
return (R,G,B)
def CMY2RGB(C,M,Y):
R = ( 1 - C )
G = ( 1 - M )
B = ( 1 - Y )
return (R,G,B)
def CMYK2CMY(C,M,Y,K):
C = ( C * ( 1 - K ) + K )
M = ( M * ( 1 - K ) + K )
Y = ( Y * ( 1 - K ) + K )
return (C,M,Y)
def CMYK2RGB(C,M,Y,K):
C,M,Y = CMYK2CMY(C,M,Y,K)
return CMY2RGB(C,M,Y)
def test_format(file):
ext = os.path.splitext(os.path.basename(file))[1].lower()
# Adobe
if ext == '.acb':
data = open(file).read(4)
if struct.unpack('4s', data)[0] == '8BCB':
format = 'adobe_acb'
elif struct.unpack('4s', data)[0] == '<?xm':
if etree.parse(file).getroot().tag == 'colorBook':
format = 'autocad_acb'
elif ext == '.aco':
data = open(file).read(2)
if struct.unpack('>h', data)[0] in (1,2):
format = 'adobe_aco'
elif ext == '.act':
if os.path.getsize(file) == 772 or os.path.getsize(file)%3 == 0:
format = 'adobe_act'
elif ext == '.ase':
data = open(file).read(4)
if struct.unpack('4s', data)[0] == 'ASEF':
format = 'adobe_ase'
elif ext == '.acf':
data = open(file).read(7)
if struct.unpack('7s', data)[0] in ('ACF 1.0','ACF 2.1'):
format = 'adobe_acf'
elif ext == '.bcf':
data = open(file).read(7)
if struct.unpack('7s', data)[0] in ('ACF 1.0','ACF 2.1','BCF 2.0'):
format = 'adobe_bcf'
elif ext == '.clr':
data = open(file).read(4)
if data == '\xff\xff\x00\x00':
format = 'adobe_clr'
# RAL
elif ext == '.bcs':
data = open(file).read(4)
if struct.unpack('b3s', data)[1] in ('clf','rgb','atl'):
format = 'ral_bcs'
# Corel
elif ext == '.cpl':
data = open(file).read(2)
if data in ('\xcc\xbc','\xcc\xdc','\xcd\xbc','\xcd\xdc','\xdd\xdc','\xdc\xdc','\xcd\xdd'):
format = 'corel_cpl'
# Quark
elif ext == '.qcl':
if etree.parse(file).getroot().tag == 'cgats17':
format = 'quark_qcl'
# ColorSchemer
elif ext == '.cs':
data = open(file).read(2)
if struct.unpack('<H', data)[0] == 3:
format = 'colorschemer'
# RIFF
elif ext == '.pal':
data = open(file).read(12)
RIFF, size, PAL = struct.unpack('<4s L 4s', data)
if RIFF == 'RIFF' and PAL == 'PAL ':
format = 'riff_pal'
if 'format' in vars():
return format
def ords2str(ords):
string = u''
for ord in ords:
string += unichr(ord)
return string.split('\x00', 1)[0]
def acb_decode_str(str):
if str[0:4] == '$$$/':
str = str.partition('=')[2]
return str.replace('^C',u'©').replace('^R',u'®')
adobe_model = {0: 'RGB', 1: 'HSV', 2: 'CMYK', 3: 'Pantone', 4: 'Focoltone', 5: 'Trumatch', 6: 'Toyo', 7: 'Lab', 8: 'Gray', 9: 'WideCMYK', 10: 'HKS', 11: 'DIC', 12: 'TotalInk', 13: 'MonitorRGB', 14: 'Duotone', 15: 'Opacity'}
bcf_model = {1: 'RGB', 2: 'CMYK',8: 'hifi', 16: 'Mixed'}
bcf_type = {1: 'Spot', 2: 'Process',8: 'Mixed', 16: 'hifi'}
corel_model = {1: 'Pantone', 2: 'CMYK100', 3: 'CMYK', 4: 'CMY', 5: 'RGB', 6: 'HSB', 7: 'HLS', 9: 'Grayscale', 10: 'B/W', 11: 'YIQ', 12: 'Lab', 15: 'Hexachrome', 17: 'CMYK', 18: 'Lab', 20: 'Registration', 21: 'Custom inks'}
def read(file):
filesize = os.path.getsize(file)
if test_format(file):
format = test_format(file)
else:
sys.stderr.write('unknown swatch format\n')
sys.exit(-1)
swatch = defaultdict(dict)
swatch['orig'] = format
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Adobe Color Book #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
if format == 'adobe_acb':
file = open(file)
file.seek(8, 1)
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
name = acb_decode_str(ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2))))
if name > u'':
swatch['swatch']['name'] = name
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
prefix = acb_decode_str(ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2))))
else:
prefix = u''
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
postfix = acb_decode_str(ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2))))
else:
postfix = u''
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
description = acb_decode_str(ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2))))
if 'description' in vars() and description > u'':
swatch['swatch']['description'] = description
nbcolors = struct.unpack('>H',file.read(2))[0]
swatch['display']['columns'] = struct.unpack('>H',file.read(2))[0]
file.seek(2, 1)
model = adobe_model[struct.unpack('>H',file.read(2))[0]]
for i in range(nbcolors):
swatch['colors'][i] = {}
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
swatch['colors'][i]['name'] = prefix+acb_decode_str(ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2))))+postfix
file.seek(6, 1)
if model == 'RGB':
R,G,B = struct.unpack('>3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
elif model == 'CMYK':
C,M,Y,K = struct.unpack('>4B',file.read(4))
swatch['colors'][i]['CMYK'] = (1-C/255,1-M/255,1-Y/255,1-K/255)
elif model == 'Lab':
L,a,b = struct.unpack('>3B',file.read(3))
swatch['colors'][i]['Lab'] = (L/2.55,a-128,b-128)
else:
sys.stderr.write('unknown color model ['+model+']\n')
if file.read(4):
if struct.unpack('>4s',file.read(4))[0] == 'spot':
swatch['swatch']['spot'] = True
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Adobe Color Swatch #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_aco':
file = open(file)
version, nbcolors = struct.unpack('>2H',file.read(4))
if version == 1 and filesize > 4+nbcolors*10:
file.seek(4+nbcolors*10)
version, nbcolors = struct.unpack('>2H',file.read(4))
for i in range(nbcolors):
swatch['colors'][i] = {}
model = adobe_model[struct.unpack('>H',file.read(2))[0]]
if model == 'CMYK':
C,M,Y,K = struct.unpack('>4H',file.read(8))
swatch['colors'][i]['CMYK'] = (1-C/65535,1-M/65535,1-Y/65535,1-K/65535)
elif model == 'WideCMYK':
C,M,Y,K = struct.unpack('>4H',file.read(8))
swatch['colors'][i]['CMYK'] = (C/10000,M/10000,Y/10000,K/10000)
elif model == 'RGB':
R,G,B = struct.unpack('>3H',file.read(6))
swatch['colors'][i]['RGB'] = (R/65535,G/65535,B/65535)
file.seek(2, 1)
elif model == 'HSV':
H,S,V = struct.unpack('>3H',file.read(6))
swatch['colors'][i]['HSV'] = (H/65535,S/65535,V/65535)
file.seek(2, 1)
elif model == 'Lab':
R,G,B = struct.unpack('>H 2h',file.read(6))
swatch['colors'][i]['Lab'] = (L/100,a/100,b/100)
file.seek(2, 1)
elif model == 'Gray':
K = struct.unpack('>H',file.read(2))
swatch['colors'][i]['Gray'] = (K/10000)
file.seek(6, 1)
else:
sys.stderr.write('unknown color model ['+model+']\n')
if version == 2:
length = struct.unpack('>L',file.read(4))[0]
if length > 0:
swatch['colors'][i]['name'] = ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2)))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Adobe Swatch Exchange #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_ase':
file = open(file)
file.seek(4)
version = struct.unpack('>2H',file.read(4))
nbblocks = struct.unpack('>L',file.read(4))[0]
for i in range(nbblocks):
swatch['colors'][i] = {}
block_type,block_size = struct.unpack('>HL',file.read(6))
if block_type == 0xc001:
swatch['colors'][i]['group'] = 'start'
elif block_type == 0xc002:
swatch['colors'][i]['group'] = 'end'
if block_size > 0:
length = struct.unpack('>H',file.read(2))[0]
if length > 0:
name = ords2str(struct.unpack('>'+str(length)+'H',file.read(length*2)))
if name > u'':
swatch['colors'][i]['name'] = name
if block_type == 0x0001:
model = struct.unpack('4s',file.read(4))[0]
if model == "CMYK":
swatch['colors'][i]['CMYK'] = struct.unpack('>4f',file.read(16))
elif model == "RGB ":
swatch['colors'][i]['RGB'] = struct.unpack('>3f',file.read(12))
elif model == "LAB ":
L,a,b = struct.unpack('>3f',file.read(12))
swatch['colors'][i]['Lab'] = (L*100,a,b)
elif model == "Gray":
swatch['colors'][i]['Gray'] = struct.unpack('>f',file.read(4))
type = struct.unpack('>H',file.read(2))[0]
if type == 0:
swatch['colors'][i]['global'] = True
elif type == 1:
swatch['colors'][i]['spot'] = True
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Adobe Color Table #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_act':
if os.path.getsize(file) == 772: # CS2
file = open(file)
file.seek(768, 0)
nbcolors = struct.unpack('>H',file.read(2))[0]
file.seek(0, 0)
else:
nbcolors = os.path.getsize(file)/3
file = open(file)
for i in range (nbcolors):
swatch['colors'][i] = {}
R,G,B = struct.unpack('3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ASCII Color Format #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_acf':
file = open(file, 'U').readlines()
version = file[0].strip()
swatch['swatch']['name'] = unicode(file[1].strip(),'macroman')
swatch['swatch']['version'] = file[2].partition('LibraryVersion: ')[2].strip()
copyright = file[3].partition('Copyright: ')[2].strip()
if copyright > '':
swatch['swatch']['copyright'] = unicode(copyright,'macroman')
description = file[4].partition('AboutMessage: ')[2].strip()
if description > '':
swatch['swatch']['description'] = unicode(description,'macroman')
name_format = file[5].partition('Names: ')[2].strip().lower() # Full Partial
swatch['swatch']['columns'] = file[6].partition('Rows: ')[2].strip()
swatch['swatch']['rows'] = file[7].partition('Columns: ')[2].strip()
nbcolors = eval(file[8].partition('Entries: ')[2].strip())
prefix = file[9].partition('Prefix: ')[2].strip()
if prefix > '':
prefix = prefix + ' '
suffix = file[10].partition('Suffix: ')[2].strip()
if suffix > '':
suffix = ' ' + suffix
type = file[11].partition('Type: ')[2].strip() # hifi Process Spot Mixed
if type == 'Spot':
swatch['swatch']['spot'] = True
models = file[12].partition('Models: ')[2].strip().split() # hifi Lab RGB CMYK
swatch['swatch']['preferredmodel'] = file[13].partition('PreferredModel: ')[2].strip()
pos = 14
if version == 'ACF 2.1':
nbinks = int(file[pos].partition('Inks: ')[2].strip())
pos = pos+1
swatch['swatch']['inks'] = []
for i in range(nbinks):
swatch['swatch']['inks'].append(file[pos].strip())
pos = pos+1
pos = pos+1
for i in range(nbcolors):
swatch['colors'][i] = {}
for model in models:
colors = file[pos].strip().split()
for k in range(len(colors)):
if model == 'RGB':
colors[k] = round(eval(colors[k])/65535)
else:
colors[k] = eval(colors[k])
swatch['colors'][i][model] = tuple(colors)
pos = pos+1
if type == 'Mixed':
col_type = file[pos].strip()
if col_type == 'Spot':
swatch['colors'][i]['spot'] = True
pos = pos+1
swatch['colors'][i]['name'] = unicode(prefix+file[pos].strip()+suffix,'macroman')
pos = pos+1
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Binary Color Format #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_bcf':
file = open(file)
version = struct.unpack('8s',file.read(8))[0].split('\x00', 1)[0]
name = struct.unpack('32s',file.read(32))[0].split('\x00', 1)[0]
if name > '':
swatch['swatch']['name'] = unicode(name,'macroman')
swatch['swatch']['version'] = struct.unpack('8s',file.read(8))[0].split('\x00', 1)[0]
copyright = struct.unpack('32s',file.read(32))[0].split('\x00', 1)[0]
if copyright > '':
swatch['swatch']['copyright'] = unicode(copyright,'macroman')
description = struct.unpack('512s',file.read(512))[0].split('\x00', 1)[0]
if description > '':
swatch['swatch']['description'] = unicode(description,'macroman')
names, swatch['display']['columns'], swatch['display']['rows'], nbcolors = struct.unpack('>4H',file.read(8))
prefix = struct.unpack('12s',file.read(12))[0].split('\x00', 1)[0]
if prefix > '':
prefix = prefix + ' '
suffix = struct.unpack('4s',file.read(4))[0].split('\x00', 1)[0]
if suffix > '':
suffix = ' ' + suffix
type, XYZ, CMYK, RGB, preferredmodel = struct.unpack('>5h',file.read(10))
swatch['swatch']['preferredmodel'] = bcf_model[preferredmodel]
if version in ('ACF 2.1','BCF 2.0'):
extender = struct.unpack('>H',file.read(2))[0]
if extender == 1:
description2 = struct.unpack('100s',file.read(100))[0].split('\x00', 1)[0]
swatch['swatch']['description'] = swatch['swatch']['description']+unicode(description2,'macroman')
inks,nbinks,Lab = struct.unpack('>3H',file.read(6))
file.seek(24, 1)
if inks == 1:
swatch['swatch']['inks'] = []
for i in range(nbinks):
swatch['swatch']['inks'] .append(struct.unpack('>10s 10s H 32s',file.read(54)))
for i in range(nbcolors):
swatch['colors'][i] = {}
if XYZ == 1:
X,Y,Z = struct.unpack('>3H',file.read(6))
swatch['colors'][i]['XYZ'] = (X/65.535,Y/65.535,Z/65.535)
elif 'Lab' in vars() and Lab == 1:
swatch['colors'][i]['Lab'] = struct.unpack('>3h',file.read(6))
else:
file.seek(6, 1)
if CMYK == 1:
C,M,Y,K = struct.unpack('>4H',file.read(8))
swatch['colors'][i]['CMYK'] = (C/65535,M/65535,Y/65535,K/65535)
else:
file.seek(8, 1)
if RGB == 1:
R,G,B = struct.unpack('>3H',file.read(6))
swatch['colors'][i]['RGB'] = (round(R/65535),round(G/65535),round(B/65535))
else:
file.seek(6, 1)
if version in ('ACF 2.1','BCF 2.0') and type in (8,16):
col_nbinks = struct.unpack('>H',file.read(2))[0]
hifi = []
for j in range(col_nbinks):
hifi.append( struct.unpack('>2H',file.read(4)))
swatch['colors'][i]['hifi'] = tuple(hifi)
file.seek((8-col_nbinks)*4, 1)
col_type = struct.unpack('>H',file.read(2))[0]
if col_type == 1:
swatch['colors'][i]['spot'] = True
if version in ('ACF 2.1','BCF 2.0') and type in (8,16):
col_preferredmodel = struct.unpack('>H',file.read(2))[0]
swatch['colors'][i]['preferredmodel'] = bcf_model[col_preferredmodel]
swatch['colors'][i]['name'] = prefix+struct.unpack('32s',file.read(32))[0].split('\x00', 1)[0]+suffix
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Flash Color Set #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'adobe_clr':
file = open(file)
file.seek(16, 1)
nbcolors = struct.unpack('<H',file.read(2))[0]
file.seek(15, 1)
for i in range(nbcolors):
swatch['colors'][i] = {}
file.seek(1, 1)
R,G,B,a = struct.unpack('4B',file.read(4))
swatch['colors'][i]['RGBa'] = (R/255,G/255,B/255,a/255)
file.seek(2, 1)
H,S,L = struct.unpack('<3H',file.read(6))
swatch['colors'][i]['HLS'] = (H/240,L/240,S/240)
file.seek(2, 1)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# AutoCAD Color Book #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'autocad_acb':
xml = etree.parse(file).getroot()
swatch['swatch']['name'] = xml.getiterator('bookName')[0].text
if len(xml.getiterator('majorVersion')) > 0:
swatch['swatch']['version'] = xml.getiterator('majorVersion')[0].text+'.'+xml.getiterator('minorVersion')[0].text
nbcolors = len(xml.getiterator('colorEntry'))
swatch['display']['columns'] = 0
i = 0
for colorPage in xml.getiterator('colorPage'):
swatch['display']['columns'] = max(swatch['display']['columns'],len(colorPage.getiterator('colorEntry')))
breaks = []
encrypted = 0
for colorPage in xml.getiterator('colorPage'):
for colorEntry in colorPage.getiterator('colorEntry'):
swatch['colors'][i] = {}
swatch['colors'][i]['name'] = colorEntry.find('colorName').text
if colorEntry.find('RGB8Encrypt'):
encrypted = 1
elif colorEntry.find('RGB8'):
swatch['colors'][i]['RGB'] = (eval(colorEntry.find('RGB8').find('red').text)/255,eval(colorEntry.find('RGB8').find('green').text)/255,eval(colorEntry.find('RGB8').find('blue').text)/255)
i = i+1
if len(colorPage.getiterator('colorEntry')) < swatch['display']['columns'] and i<nbcolors:
breaks.append(i)
if len(breaks)>0:
swatch['display']['breaks'] = breaks
if encrypted == 1:
sys.stderr.write("this script can't decode encrypted RGB values\n")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# QuarkXPress Color Library #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'quark_qcl':
xml = etree.parse(file).getroot()
swatch['swatch']['name'] = xml.getiterator('file_descriptor')[0].text
swatch['swatch']['copyright'] = xml.getiterator('originator')[0].text
swatch['swatch']['preferredmodel'] = xml.getiterator('default_color_space')[0].text.strip()
name_field_info = xml.getiterator('name_field_info')
swatch['swatch']['name_format'] = {}
prefix = {}
suffix = {}
for name in name_field_info:
nid = eval(name.attrib['format_id'])-1
prefix[nid], suffix[nid] = name.attrib['long_form'].split('%n')
ui_spec = os.path.dirname(file)+'/'+xml.getiterator('ui_spec')[0].text
if os.path.isfile(ui_spec):
ui = etree.parse(ui_spec).getroot()
swatch['display']['columns'] = eval(ui.getiterator('rows_per_page')[0].text)
breaks = ui.getiterator('column_break')
if len(breaks)>0:
for i in range(len(breaks)):
breaks[i] = eval(breaks[i].text)
swatch['display']['breaks'] = breaks
else:
sys.stderr.write('ui file '+ui_spec+' doesn\'t exist\n')
fields = xml.getiterator('field_info')
data_format = {}
for field in fields:
data_format[field.attrib['name']] = field.attrib['pos']
colors = xml.getiterator('tr')
i = 0
for color in colors:
swatch['colors'][i] = {}
name = color.getchildren()[eval(data_format['SAMPLE_ID'])-1].text
if data_format.has_key('NAME_FORMAT_ID'):
nid = eval(color.getchildren()[eval(data_format['NAME_FORMAT_ID'])-1].text)-1
swatch['colors'][i]['name'] = prefix[nid]+name+suffix[nid]
else:
swatch['colors'][i]['name'] = prefix+name
if data_format.has_key('LAB_L'):
swatch['colors'][i]['Lab'] = (eval(color.getchildren()[eval(data_format['LAB_L'])-1].text),\
eval(color.getchildren()[eval(data_format['LAB_A'])-1].text),\
eval(color.getchildren()[eval(data_format['LAB_B'])-1].text))
if data_format.has_key('RGB_R'):
swatch['colors'][i]['RGB'] = (eval(color.getchildren()[eval(data_format['RGB_R'])-1].text),\
eval(color.getchildren()[eval(data_format['RGB_G'])-1].text),\
eval(color.getchildren()[eval(data_format['RGB_B'])-1].text))
if data_format.has_key('CMYK_C'):
swatch['colors'][i]['CMYK'] = (eval(color.getchildren()[eval(data_format['CMYK_C'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['CMYK_M'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['CMYK_Y'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['CMYK_K'])-1].text)/100)
if data_format.has_key('PC6_1'):
swatch['colors'][i]['6CLR'] = (eval(color.getchildren()[eval(data_format['PC6_1'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['PC6_2'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['PC6_3'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['PC6_4'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['PC6_5'])-1].text)/100,\
eval(color.getchildren()[eval(data_format['PC6_6'])-1].text)/100)
i = i+1
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# RAL #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'ral_bcs':
file = open(file)
offset, sig = struct.unpack('B 3s',file.read(4))
if sig == 'clf':
swatch['swatch']['spot'] = True
file.seek(offset+1, 0)
nbcolors = struct.unpack('<H',file.read(2))[0]
length = struct.unpack('B',file.read(1))[0]
name_tmp = struct.unpack(str(length)+'s',file.read(length))[0].split(':')
swatch['swatch']['name'] = name_tmp[0].split('English_')[1]
if name_tmp[1].split('German_')[1] != swatch['swatch']['name']:
swatch['swatch']['name_de'] = name_tmp[1].split('German_')[1]
file.seek(1, 1)
for i in range(nbcolors):
swatch['colors'][i] = {}
length = struct.unpack('B',file.read(1))[0]
if length > 0:
swatch['colors'][i]['name'] = struct.unpack(str(length)+'s',file.read(length))[0]
swatch['colors'][i]['Lab'] = struct.unpack('<3f',file.read(12))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# RIFF Palette #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'riff_pal':
file = open(file)
file.seek(12, 0)
chunk = struct.unpack('<4s L', file.read(8))
while chunk[0] != 'data':
file.seek(chunk[1], 1)
chunk = struct.unpack('<4s L', file.read(8))
version, nbcolors = struct.unpack('<2H',file.read(4))
for i in range(nbcolors):
swatch['colors'][i] = {}
R,G,B = struct.unpack('3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
file.seek(1, 1)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# ColorSchemer #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'colorschemer':
file = open(file)
version, nbcolors = struct.unpack('<2H',file.read(4))
file.seek(4, 1)
for i in range(nbcolors):
swatch['colors'][i] = {}
R,G,B = struct.unpack('3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
file.seek(1, 1)
length = struct.unpack('<L',file.read(4))[0]
if length > 0:
swatch['colors'][i]['name'] = struct.unpack(str(length)+'s',file.read(length))[0]
file.seek(11, 1)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# CorelDRAW Palette #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
elif format == 'corel_cpl':
file = open(file)
version = file.read(2)
if version == '\xdc\xdc': #custom palettes
length = struct.unpack('B',file.read(1))[0]
if length > 0:
swatch['swatch']['name'] = struct.unpack(str(length)+'s',file.read(length))[0]
nbcolors = struct.unpack('<H',file.read(2))[0]
elif version in ('\xcc\xbc','\xcc\xdc'):
nbcolors = struct.unpack('<H',file.read(2))[0]
else:
nbheaders = struct.unpack('<L',file.read(4))[0]
headers = {}
for i in range(nbheaders):
id,offset = struct.unpack('<2L',file.read(8))
headers[id] = offset
# Header 0: Name
file.seek(headers[0], 0)
length = struct.unpack('B',file.read(1))[0]
if length > 0:
if version == '\xcd\xdc':
swatch['swatch']['name'] = struct.unpack(str(length)+'s',file.read(length))[0]
else:
swatch['swatch']['name'] = ords2str(struct.unpack('<'+str(length)+'H',file.read(length*2)))
# Header 1: Palette Type
file.seek(headers[1], 0)
type = struct.unpack('<H',file.read(2))[0]
# Header 2: Number of colors
file.seek(headers[2], 0)
nbcolors = struct.unpack('<H',file.read(2))[0]
# Header 3: Custom inks
if 3 in headers:
file.seek(headers[3], 0)
nbinks = struct.unpack('<H',file.read(2))[0]
swatch['swatch']['inks'] = struct.unpack('<'+str(nbinks)+'H',file.read(nbinks*2))
# Header 5: UI informations
if 5 in headers:
file.seek(headers[5], 0)
swatch['display']['columns'],swatch['display']['rows'] = struct.unpack('<2H',file.read(4))
file.seek(headers[2]+2, 0)
if version in ('\xcd\xbc','\xcd\xdc','\xcd\xdd') and type < 38 and type not in(5,16):
long = True
else:
long = False
row = {}
col = {}
breaks = []
for i in range(nbcolors):
swatch['colors'][i] = {}
if long:
file.seek(4, 1)
model = struct.unpack('<H',file.read(2))[0]
file.seek(2, 1)
if model == 1:
file.seek(4, 1)
swatch['colors'][i]['PMS'] = struct.unpack('<2H',file.read(4))
elif model == 2:
file.seek(4, 1)
C,M,Y,K = struct.unpack('4B',file.read(4))
swatch['colors'][i]['CMYK'] = (C/100,M/100,Y/100,K/100)
elif model in (3,17):
file.seek(4, 1)
C,M,Y,K = struct.unpack('4B',file.read(4))
swatch['colors'][i]['CMYK'] = (C/255,M/255,Y/255,K/255)
elif model == 4:
file.seek(4, 1)
C,M,Y = struct.unpack('3B',file.read(3))
swatch['colors'][i]['CMY'] = (C/255,M/255,Y/255)
file.seek(1, 1)
elif model in (5,21):
file.seek(4, 1)
B,G,R = struct.unpack('3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
file.seek(1, 1)
elif model == 6:
file.seek(4, 1)
H,S,V = struct.unpack('<H2B',file.read(4))
swatch['colors'][i]['HSV'] = (H/360,S/255,V/255)
elif model == 7:
file.seek(4, 1)
H,L,S = struct.unpack('<H2B',file.read(4))
swatch['colors'][i]['HLS'] = (H/360,L/255,S/255)
elif model == 9:
file.seek(4, 1)
K = struct.unpack('B',file.read(1))[0]
swatch['colors'][i]['Gray'] = (1-K/255)
file.seek(3, 1)
elif model == 11:
file.seek(4, 1)
Y,I,Q = struct.unpack('3B',file.read(3))
swatch['colors'][i]['YIQ'] = (Y/255,I/255,Q/255)
file.seek(1, 1)
elif model == 12:
file.seek(4, 1)
L,a,b = struct.unpack('B 2b',file.read(3))
swatch['colors'][i]['Lab'] = (L/2.55,a,b)
file.seek(1, 1)
elif model == 15:
file.seek(2, 1)
Y,O,M,C,G,K = struct.unpack('6B',file.read(3))
swatch['colors'][i]['6CLR'] = (C/255,M/255,Y/255,K/255,O/255,G/255)
elif model == 18:
file.seek(4, 1)
L,a,b = struct.unpack('3B',file.read(3))
swatch['colors'][i]['Lab'] = (L/2.55,a-128,b-128)
file.seek(1, 1)
else:
file.seek(8, 1)
if long:
model2 = struct.unpack('<H',file.read(2))[0]
file.seek(2, 1)
if model2 == model:
file.seek(8, 1)
else:
if model2 == 1:
file.seek(4, 1)
swatch['colors'][i]['PMS'] = struct.unpack('<2H',file.read(4))
elif model2 == 2:
file.seek(4, 1)
C,M,Y,K = struct.unpack('4B',file.read(4))
swatch['colors'][i]['CMYK'] = (C/100,M/100,Y/100,K/100)
elif model2 in (3,17):
file.seek(4, 1)
C,M,Y,K = struct.unpack('4B',file.read(4))
swatch['colors'][i]['CMYK'] = (C/255,M/255,Y/255,K/255)
elif model2 == 4:
file.seek(4, 1)
C,M,Y = struct.unpack('3B',file.read(3))
swatch['colors'][i]['CMY'] = (C/255,M/255,Y/255)
file.seek(1, 1)
elif model2 in (5,21):
file.seek(4, 1)
B,G,R = struct.unpack('3B',file.read(3))
swatch['colors'][i]['RGB'] = (R/255,G/255,B/255)
file.seek(1, 1)
elif model2 == 6:
file.seek(4, 1)
H,S,V = struct.unpack('<H2B',file.read(4))
swatch['colors'][i]['HSV'] = (H/360,S/255,V/255)
elif model2 == 7:
file.seek(4, 1)
H,L,S = struct.unpack('<H2B',file.read(4))
swatch['colors'][i]['HLS'] = (H/360,L/255,S/255)
elif model2 == 9:
file.seek(4, 1)
K = struct.unpack('B',file.read(1))[0]
swatch['colors'][i]['Gray'] = (1-K/255)
file.seek(3, 1)
elif model2 == 11:
file.seek(4, 1)
Y,I,Q = struct.unpack('3B',file.read(3))
swatch['colors'][i]['YIQ'] = (Y/255,I/255,Q/255)
file.seek(1, 1)
elif model == 12:
file.seek(4, 1)
L,a,b = struct.unpack('B 2b',file.read(3))
swatch['colors'][i]['Lab'] = (L/2.55,a,b)
file.seek(1, 1)
elif model2 == 15:
file.seek(2, 1)
Y,O,M,C,G,K = struct.unpack('6B',file.read(3))
swatch['colors'][i]['6CLR'] = (C/255,M/255,Y/255,K/255,O/255,G/255)
elif model2 == 18:
file.seek(4, 1)
L,a,b = struct.unpack('3B',file.read(3))
swatch['colors'][i]['Lab'] = (L/2.55,a-128,b-128)
file.seek(1, 1)
else:
file.seek(8, 1)
length = struct.unpack('B',file.read(1))[0]
if length > 0:
if version in ('\xdc\xdc','\xcc\xdc') or (version == '\xcd\xdc' and type not in (16)):
swatch['colors'][i]['name'] = struct.unpack(str(length)+'s',file.read(length))[0]
else:
swatch['colors'][i]['name'] = ords2str(struct.unpack('<'+str(length)+'H',file.read(length*2)))
if version == '\xcd\xdd':
row[i], col[i] = struct.unpack('<2L',file.read(8))
if row[i] > 0 and col[i] == 0 and col[i-1] < swatch['display']['columns']-1:
breaks.append(i)
file.seek(4, 1)
if len(breaks)>0:
swatch['display']['breaks'] = breaks
return swatch
def toRGB8(color):
if 'RGB' in color:
R,G,B = color['RGB']
elif 'HSV' in color:
H,S,V = color['HSV']
R,G,B = HSV2RGB(H,S,V)
elif 'HLS' in color:
H,L,S = color['HLS']
R,G,B = HSL2RGB(H,S,L)
elif 'Lab' in color:
L,a,b = color['Lab']
return Lab2RGB8(L,a,b)
elif 'CMYK' in color:
C,M,Y,K = color['CMYK']
R,G,B = CMYK2RGB(C,M,Y,K)
elif 'Gray' in color:
R = G = B = 1-color['Gray'][0]
else:
return False
return (int(round(R*255)),int(round(G*255)),int(round(B*255)))
def hex2(val):
return hex(int(round(val)))[2:].rjust(2,'0')
def write(swatch, format):
if format == 'gimp':
gpl = 'GIMP Palette\n'
if 'name' in swatch['swatch']:
gpl += 'Name: '+swatch['swatch']['name']+'\n'
if 'columns' in swatch['display']:
gpl += 'Columns: '+str(swatch['display']['columns'])+'\n'
gpl += '#'
for key,color in swatch['colors'].items():
if toRGB8(color):
R,G,B = toRGB8(color)
gpl += '\n'+str(R).rjust(3)+' '+str(G).rjust(3)+' '+str(B).rjust(3)
if 'name' in color:
gpl += '\t'+color['name']
return gpl.encode('utf-8')
elif format == 'scribus':
scsw = '<?xml version="1.0" encoding="UTF-8"?>\n<swatch>\n'
for key,color in swatch['colors'].items():
if 'group' not in color:
scsw += '\t<COLOR '
if 'CMYK' in color:
C,M,Y,K = color['CMYK']
scsw += 'CMYK="#'+hex2(C*255)+hex2(M*255)+hex2(Y*255)+hex2(K*255)+'"'
elif 'Gray' in color:
K = color['Gray'][0]
scsw += 'CMYK="#000000'+hex2(K*255)+'"'
else:
if toRGB8(color):
R,G,B = toRGB8(color)
scsw += 'RGB="#'+hex2(R)+hex2(G)+hex2(B)+'"'
if 'name' in color:
scsw += ' NAME="'+color['name']+'"'
if 'spot' in swatch['swatch'] or 'spot' in color:
scsw += ' Spot="1"'
scsw += ' />\n'
scsw += '</swatch>'
return scsw.encode('utf-8')
elif format == 'create':
create = '<?xml version="1.0" encoding="UTF-8"?>\n'
create += '<colors\n xmlns:xlink="http://www.w3.org/1999/xlink"\n xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
if 'swatch' in swatch:
create += ' <metadata>\n'
if 'name' in swatch['swatch']:
create += ' <dc:title>'+swatch['swatch']['name']+'</dc:title>\n'
if 'name_de' in swatch['swatch']:
create += ' <dc:title xml:lang="de-DE">'+swatch['swatch']['name_de']+'</dc:title>\n'
if 'description' in swatch['swatch']:
create += ' <dc:description>'+swatch['swatch']['description']+'</dc:description>\n'
if 'copyright' in swatch['swatch']:
create += ' <dc:rights>'+swatch['swatch']['copyright']+'</dc:rights>\n'
if 'version' in swatch['swatch']:
create += ' <version>'+swatch['swatch']['version']+'</version>\n'
create += ' </metadata>\n'
if 'display' in swatch:
create += ' <display>\n'
if 'columns' in swatch['display']:
create += ' <columns>'+str(swatch['display']['columns'])+'</columns>\n'
if 'rows' in swatch['display']:
create += ' <rows>'+str(swatch['display']['rows'])+'</rows>\n'
if 'breaks' in swatch['display']:
create += ' <breaks>'+str(swatch['display']['breaks']).strip('[]')+'</breaks>\n'
create += ' </display>\n'
group = 0
for key,color in swatch['colors'].items():
if 'group' in color:
if color['group'] == 'start':
create += ' <colorgroup'
if 'name' in color:
create += ' name="'+color['name']+'"'
create += '>\n'
group = 1
elif color['group'] == 'end':
create += ' </colorgroup>\n'
group = 0
else:
if group == 1:
create += ' '
create += ' <color'
if 'name' in color:
create += ' name="'+color['name']+'"'
if 'spot' in swatch['swatch'] or 'spot' in color:
create += ' spot="1"'
create += '>\n'
if 'RGB' in color:
R,G,B = color['RGB']
if group == 1:
create += ' '
create += ' <RGB r="'+str(round(R,4))+'" g="'+str(round(G,4))+'" b="'+str(round(B,4))+'" />\n'
if 'HSV' in color:
H,S,V = color['HSV']
if group == 1:
create += ' '
create += ' <HSV h="'+str(int(round(H*360)))+'" s="'+str(round(S,4))+'" v="'+str(round(V,4))+'" />\n'
if 'HLS' in color:
H,L,S = color['HLS']
if group == 1:
create += ' '
create += ' <HLS h="'+str(int(round(H*360)))+'" l="'+str(round(L,4))+'" s="'+str(round(S,4))+'" />\n'
if 'CMYK' in color:
C,M,Y,K = color['CMYK']
if group == 1:
create += ' '
create += ' <CMYK c="'+str(round(C,4))+'" m="'+str(round(M,4))+'" y="'+str(round(Y,4))+'" k="'+str(round(K,4))+'" />\n'
if 'CMY' in color:
C,M,Y = color['CMY']
if group == 1:
create += ' '
create += ' <CMY c="'+str(round(C,4))+'" m="'+str(round(M,4))+'" y="'+str(round(Y,4))+'" />\n'
if 'Gray' in color:
K = color['Gray'][0]
if group == 1:
create += ' '
create += ' <Gray k="'+str(round(C,4))+'" />\n'
if 'Lab' in color:
L,a,b = color['Lab']
if group == 1:
create += ' '
create += ' <Lab L="'+str(round(L,4))+'" a="'+str(round(a,4))+'" b="'+str(round(b,4))+'" />\n'
if 'XYZ' in color:
X,Y,Z = color['XYZ']
if group == 1:
create += ' '
create += ' <XYZ x="'+str(round(L,4))+'" y="'+str(round(a,4))+'" z="'+str(round(b,4))+'" />\n'
if '6CLR' in color:
C,M,Y,K,O,G = color['6CLR']
if group == 1:
create += ' '
create += ' <6CLR c="'+str(round(C,4))+'" m="'+str(round(M,4))+'" y="'+str(round(Y,4))+'" k="'+str(round(K,4))+'" o="'+str(round(O,4))+'" g="'+str(round(G,4))+'" />\n'
if 'preferredmodel' in color or 'preferredmodel' in swatch['swatch']:
if 'preferredmodel' in color:
preferredmodel = color['preferredmodel']
else:
preferredmodel = swatch['swatch']['preferredmodel']
if group == 1:
create += ' '
create += ' <preferredmodel>'+preferredmodel+'</preferredmodel>\n'
if group == 1:
create += ' '
create += ' </color>\n'
create += '</colors>'
return create.encode('utf-8')
elif format == 'dump':
return swatch
else:
sys.stderr.write('unsupported output format\n')
def main():
args = sys.argv[1:]
if len(args) != 2:
sys.stderr.write('usage: python swatch_convertor.py inputfile outputformat[gimp|scribus|create|dump]')
sys.exit(-1)
file = args[0]
filename = os.path.basename(file)
basename = os.path.splitext(filename)[0]
if not os.path.isfile(file):
sys.stderr.write('file '+file+' doesn\'t exist')
sys.exit(-1)
if os.path.getsize(file) == 0:
sys.stderr.write('empty file')
sys.exit(-1)
print write(read(file),args[1])
if __name__ == '__main__':
main()
_______________________________________________
CREATE mailing list
CREATE@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/create