Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit af23fb283da7aff63b1adacfe7d050bb06ca1e37 @nsfmc committed Dec 27, 2012
Showing with 248 additions and 0 deletions.
  1. +19 −0 LICENSE
  2. +51 −0 README.md
  3. +28 −0 setup.py
  4. +77 −0 swatch/__init__.py
  5. +73 −0 swatch/parser.py
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2011 by Marcos Ojeda, generic.cx
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
@@ -0,0 +1,51 @@
+# Swatch
+
+swatch is a parser for adobe swatch exchange files
+
+Copyright (c) 2012 Marcos A Ojeda http://generic.cx/
+
+
+http://iamacamera.org/default.aspx?id=109 by Carl Camera and
+http://www.colourlovers.com/ase.phps by Chris Williams
+
+
+swatch.parse reads in an ase file and converts it to a list of colors and
+palettes. colors are simple dicts of the form
+
+ {
+ 'name': u'color name',
+ 'data': {
+ 'mode': 'RGB',
+ 'values': [1.0, 1.0, 1.0]
+ }
+ }
+
+the values provided vary between color mode. For all color modes, the
+value is always a list of floats.
+
+RGB: three floats between [0,1] corresponding to RGB
+CMYK: four floats between [0,1] inclusive, corresponding to CMYK
+Gray: one float between [0,1] with 1 being white, 0 being black
+LAB: three floats. The first L, is ranged from 0,1. Both A and B are
+floats ranging from [-128.0,127.0]. I believe illustrator just crops
+these to whole values, though.
+
+Palettes are also dicts, but they have an attribute named swatches which
+contains a list of colors contained within the palette.
+
+ {
+ 'name': u'accent colors',
+ 'swatches': [
+ {color}, {color}, ..., {color}
+ ]
+ }
+
+Because Adobe Illustrator lets swatches exist either inside and outside
+of palettes, the output of swatch.parse is a list that may contain
+swatches and palettes, i.e. [ [swatch|palette]* ]
+
+Here's an example:
+
+>>> import swatch
+>>> swatch.parse("simple palette.ase")
+[{'data': {'mode': 'RGB', 'values': [1.0, 1.0, 1.0]}, 'name': u'Bright White'}]
@@ -0,0 +1,28 @@
+from distutils.core import setup
+import codecs
+from swatch import __version__ as VERSION
+
+README = codecs.open('README.md', encoding='utf-8').read()
+LICENSE = codecs.open('LICENSE', encoding='utf-8').read()
+
+setup(
+ name='swatch',
+ version=VERSION,
+ author='Marcos A Ojeda',
+ author_email='marcos@generic.cx',
+ packages=['swatch'],
+ license=LICENSE,
+ description='a parser for adobe swatch exchange files'
+ long_description=README,
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Artistic Software',
+ 'Topic :: Multimedia :: Graphics',
+ 'Topic :: Multimedia :: Graphics :: Graphics Conversion',
+ 'Topic :: Software Development :: Libraries :: Python Modules'
+ ]
+)
@@ -0,0 +1,77 @@
+# encoding: utf-8
+"""
+swatch, a parser for adobe swatch exchange files
+Copyright (c) 2012 Marcos A Ojeda http://generic.cx/
+
+With notes from
+http://iamacamera.org/default.aspx?id=109 by Carl Camera and
+http://www.colourlovers.com/ase.phps by Chris Williams
+
+All Rights Reserved
+MIT Licensed, see LICENSE.TXT for details
+"""
+
+
+__title__ = 'swatch'
+__version__ = '0.1.0'
+__author__ = 'Marcos Ojeda'
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2012 Marcos A Ojeda'
+
+
+from . import parser
+import struct
+
+
+def parse(filename):
+ """parses a .ase file and returns a list of colors and palettes
+
+ swatch.parse reads in an ase file and converts it to a list of colors and
+ palettes. colors are simple dicts of the form
+
+ {
+ 'name': u'color name',
+ 'data': {
+ 'mode': 'RGB',
+ 'values': [1.0, 1.0, 1.0]
+ }
+ }
+
+ the values provided vary between color mode. For all color modes, the
+ value is always a list of floats.
+
+ RGB: three floats between [0,1] corresponding to RGB
+ CMYK: four floats between [0,1] inclusive, corresponding to CMYK
+ Gray: one float between [0,1] with 1 being white, 0 being black
+ LAB: three floats. The first L, is ranged from 0,1. Both A and B are
+ floats ranging from [-128.0,127.0]. I believe illustrator just crops
+ these to whole values, though.
+
+ Palettes are also dicts, but they have an attribute named swatches which
+ contains a list of colors contained within the palette.
+
+ {
+ 'name': u'accent colors',
+ 'swatches': [
+ {color}, {color}, ..., {color}
+ ]
+ }
+
+ Because Adobe Illustrator lets swatches exist either inside and outside
+ of palettes, the output of swatch.parse is a list that may contain
+ swatches and palettes, i.e. [ [swatch|palette]* ]
+
+ Here's an example:
+
+ >>> import swatch
+ >>> swatch.parse("simple palette.ase")
+ [{'data': {'mode': 'RGB', 'values': [1.0, 1.0, 1.0]}, 'name': u'Bright White'}]
+
+ """
+ with open(filename, "rb") as data:
+ header, version_major, version_minor, chunk_count = struct.unpack("!4sHHI", data.read(12))
+
+ assert header == "ASEF"
+ assert (version_major, version_minor) == (1, 0)
+
+ return [c for c in parser.parse_chunk(data)]
@@ -0,0 +1,73 @@
+# encoding: utf-8
+"""
+swatch, a parser for adobe swatch exchange files
+Copyright (c) 2012 Marcos A Ojeda http://generic.cx/
+
+With notes from
+http://iamacamera.org/default.aspx?id=109 and
+http://www.colourlovers.com/ase.phps
+
+All Rights Reserved
+MIT Licensed, see LICENSE.TXT for details
+"""
+import struct
+import os
+
+
+def parse_chunk(fd):
+ chunk_type = fd.read(2)
+ while chunk_type:
+ if chunk_type == '\x00\x01':
+ # a single color
+ o = dict_for_chunk(fd)
+ yield o
+
+ elif chunk_type == '\xC0\x01':
+ # folder/palate
+ o = dict_for_chunk(fd)
+ o['swatches'] = [x for x in colors(fd)]
+ yield o
+
+ elif chunk_type == '\xC0\x02':
+ # this signals the end of a folder
+ assert fd.read(4) == '\x00\x00\x00\x00'
+ pass
+
+ else:
+ # the file is malformed?
+ assert chunk_type in [
+ '\xC0\x01', '\x00\x01', '\xC0\x02', '\x00\x02']
+ pass
+
+ chunk_type = fd.read(2)
+
+
+def colors(fd):
+ chunk_type = fd.read(2)
+ while chunk_type in ['\x00\x01', '\x00\x02']:
+ d = dict_for_chunk(fd)
+ yield d
+ chunk_type = fd.read(2)
+ fd.seek(-2, os.SEEK_CUR)
+
+
+def dict_for_chunk(fd):
+ chunk_length = struct.unpack(">I", fd.read(4))[0]
+ data = fd.read(chunk_length)
+
+ title_length = (struct.unpack(">H", data[:2])[0]) * 2
+ title = data[2:2 + title_length].decode("utf-16be").strip('\0')
+ color_data = data[2 + title_length:]
+
+ output = {
+ 'name': title,
+ }
+
+ if color_data:
+ fmt = {'RGB': '!fff', 'Gray': '!f', 'CMYK': '!ffff', 'LAB': '!fff'}
+ color_type = struct.unpack("!4s", color_data[:4])[0].strip()
+ color_values = list(struct.unpack(fmt[color_type], color_data[4:-2]))
+ data = {'mode': color_type, 'values': color_values}
+ output.update(data=data)
+
+ return output

0 comments on commit af23fb2

Please sign in to comment.