rename texmessage.loadfd to texmessage.loaddef and allow for .def and .fd files
[PyX/mjg.git] / pyx / color.py
blob3d544de9473ca422cf2998255af8400556618656
1 #!/usr/bin/env python
2 # -*- coding: ISO-8859-1 -*-
5 # Copyright (C) 2002-2004 Jörg Lehmann <joergl@users.sourceforge.net>
6 # Copyright (C) 2003-2005 Michael Schindler <m-schindler@users.sourceforge.net>
7 # Copyright (C) 2002-2004 André Wobst <wobsta@users.sourceforge.net>
9 # This file is part of PyX (http://pyx.sourceforge.net/).
11 # PyX is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # PyX is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with PyX; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 import colorsys, math
26 import attr, style, pdfwriter
28 # device-dependend (nonlinear) functions for color conversion
29 # UCRx : [0,1] -> [-1, 1] UnderColorRemoval (removes black from c, y, m)
30 # BG : [0,1] -> [0, 1] BlackGeneration (generate the black from the nominal k-value)
31 # as long as we have no further knowledge we define them linearly with constants 1
32 def _UCRc(x): return x
33 def _UCRm(x): return x
34 def _UCRy(x): return x
35 def _BG(x): return x
37 def set(UCRc=None, UCRm=None, UCRy=None, BG=None):
38 global _UCRc
39 global _UCRm
40 global _UCRy
41 global _BG
43 if UCRc is not None:
44 _UCRc = UCRc
45 if UCRm is not None:
46 _UCRm = UCRm
47 if UCRy is not None:
48 _UCRy = UCRy
49 if BG is not None:
50 _BG = BG
53 class color(attr.exclusiveattr, style.strokestyle, style.fillstyle):
55 """base class for all colors"""
57 def __init__(self):
58 attr.exclusiveattr.__init__(self, color)
61 clear = attr.clearclass(color)
64 class grey(color):
66 """grey tones"""
68 def __init__(self, gray):
69 color.__init__(self)
70 if gray<0 or gray>1: raise ValueError
71 self.color = {"gray": gray}
73 def outputPS(self, file, writer, context):
74 file.write("%(gray)g setgray\n" % self.color)
76 def outputPDF(self, file, writer, context):
77 if context.strokeattr:
78 file.write("%(gray)f G\n" % self.color)
79 if context.fillattr:
80 file.write("%(gray)f g\n" % self.color)
82 def cmyk(self):
83 return cmyk(0, 0, 0, 1 - self.color["gray"])
85 def grey(self):
86 return self
88 def hsb(self):
89 return hsb(0, 0, self.color["gray"])
91 def rgb(self):
92 return rgb(self.color["gray"], self.color["gray"], self.color["gray"])
94 grey.black = grey(0.0)
95 grey.white = grey(1.0)
96 gray = grey
99 class rgb(color):
101 """rgb colors"""
103 def __init__(self, r=0.0, g=0.0, b=0.0):
104 color.__init__(self)
105 if r<0 or r>1 or g<0 or g>1 or b<0 or b>1: raise ValueError
106 self.color = {"r": r, "g": g, "b": b}
108 def outputPS(self, file, writer, context):
109 file.write("%(r)g %(g)g %(b)g setrgbcolor\n" % self.color)
111 def outputPDF(self, file, writer, context):
112 if context.strokeattr:
113 file.write("%(r)f %(g)f %(b)f RG\n" % self.color)
114 if context.fillattr:
115 file.write("%(r)f %(g)f %(b)f rg\n" % self.color)
117 def cmyk(self):
118 # conversion to cmy
119 c, m, y = 1 - self.color["r"], 1 - self.color["g"], 1 - self.color["b"]
120 # conversion from cmy to cmyk with device-dependent functions
121 k = min([c, m, y])
122 return cmyk(min(1, max(0, c - _UCRc(k))),
123 min(1, max(0, m - _UCRm(k))),
124 min(1, max(0, y - _UCRy(k))),
125 _BG(k))
127 def grey(self):
128 return grey(0.3*self.color["r"] + 0.59*self.color["g"] + 0.11*self.color["b"])
129 gray = grey
131 def hsb(self):
133 values = self.color.values()
134 values.sort()
135 z, y, x = values
136 r, g, b = self.color["r"], self.color["g"], self.color["b"]
137 try:
138 if r == x and g == z:
139 return hsb((5 + (x-b)/(x-z)) / 6.0, (x - z) / x, x)
140 elif r == x and g > z:
141 return hsb((1 - (x-g)/(x-z)) / 6.0, (x - z) / x, x)
142 elif g == x and b == z:
143 return hsb((1 + (x-r)/(x-z)) / 6.0, (x - z) / x, x)
144 elif g == x and b > z:
145 return hsb((3 - (x-b)/(x-z)) / 6.0, (x - z) / x, x)
146 elif b == x and r == z:
147 return hsb((3 + (x-g)/(x-z)) / 6.0, (x - z) / x, x)
148 elif b == x and r > z:
149 return hsb((5 - (x-r)/(x-z)) / 6.0, (x - z) / x, x)
150 else:
151 raise ValueError
152 except ZeroDivisionError:
153 return hsb(0, 0, x)
155 def rgb(self):
156 return self
158 rgb.red = rgb(1 ,0, 0)
159 rgb.green = rgb(0 ,1, 0)
160 rgb.blue = rgb(0 ,0, 1)
161 rgb.white = rgb(1 ,1, 1)
162 rgb.black = rgb(0 ,0, 0)
165 class hsb(color):
167 """hsb colors"""
169 def __init__(self, h=0.0, s=0.0, b=0.0):
170 color.__init__(self)
171 if h<0 or h>1 or s<0 or s>1 or b<0 or b>1: raise ValueError
172 self.color = {"h": h, "s": s, "b": b}
174 def outputPS(self, file, writer, context):
175 file.write("%(h)g %(s)g %(b)g sethsbcolor\n" % self.color)
177 def outputPDF(self, file, writer, context):
178 r, g, b = colorsys.hsv_to_rgb(self.color["h"], self.color["s"], self.color["b"])
179 rgb(r, g, b).outputPDF(file, writer, context)
181 def cmyk(self):
182 return self.rgb().cmyk()
184 def grey(self):
185 return self.rgb().grey()
186 gray = grey
188 def hsb(self):
189 return self
191 def rgb(self):
192 h, s, b = self.color["h"], self.color["s"], self.color["b"]
193 i = int(6*h)
194 f = 6*h - i
195 m, n, k = 1 - s, 1 - s*f, 1 - s*(1-f)
196 if i == 1:
197 return rgb(b*n, b, b*m)
198 elif i == 2:
199 return rgb(b*m, b, b*k)
200 elif i == 3:
201 return rgb(b*m, b*n, b)
202 elif i == 4:
203 return rgb(b*k, b*m, b)
204 elif i == 5:
205 return rgb(b, b*m, b*n)
206 else:
207 return rgb(b, b*k, b*m)
210 class cmyk(color):
212 """cmyk colors"""
214 def __init__(self, c=0.0, m=0.0, y=0.0, k=0.0):
215 color.__init__(self)
216 if c<0 or c>1 or m<0 or m>1 or y<0 or y>1 or k<0 or k>1: raise ValueError
217 self.color = {"c": c, "m": m, "y": y, "k": k}
219 def outputPS(self, file, writer, context):
220 file.write("%(c)g %(m)g %(y)g %(k)g setcmykcolor\n" % self.color)
222 def outputPDF(self, file, writer, context):
223 if context.strokeattr:
224 file.write("%(c)f %(m)f %(y)f %(k)f K\n" % self.color)
225 if context.fillattr:
226 file.write("%(c)f %(m)f %(y)f %(k)f k\n" % self.color)
228 def cmyk(self):
229 return self
231 def grey(self):
232 return grey(1 - min([1, 0.3*self.color["c"] + 0.59*self.color["m"] +
233 0.11*self.color["y"] + self.color["k"]]))
234 gray = grey
236 def hsb(self):
237 return self.rgb().hsb()
239 def rgb(self):
240 # conversion to cmy:
241 c = min(1, self.color["c"] + self.color["k"])
242 m = min(1, self.color["m"] + self.color["k"])
243 y = min(1, self.color["y"] + self.color["k"])
244 # conversion from cmy to rgb:
245 return rgb(1 - c, 1 - m, 1 - y)
247 cmyk.GreenYellow = cmyk(0.15, 0, 0.69, 0)
248 cmyk.Yellow = cmyk(0, 0, 1, 0)
249 cmyk.Goldenrod = cmyk(0, 0.10, 0.84, 0)
250 cmyk.Dandelion = cmyk(0, 0.29, 0.84, 0)
251 cmyk.Apricot = cmyk(0, 0.32, 0.52, 0)
252 cmyk.Peach = cmyk(0, 0.50, 0.70, 0)
253 cmyk.Melon = cmyk(0, 0.46, 0.50, 0)
254 cmyk.YellowOrange = cmyk(0, 0.42, 1, 0)
255 cmyk.Orange = cmyk(0, 0.61, 0.87, 0)
256 cmyk.BurntOrange = cmyk(0, 0.51, 1, 0)
257 cmyk.Bittersweet = cmyk(0, 0.75, 1, 0.24)
258 cmyk.RedOrange = cmyk(0, 0.77, 0.87, 0)
259 cmyk.Mahogany = cmyk(0, 0.85, 0.87, 0.35)
260 cmyk.Maroon = cmyk(0, 0.87, 0.68, 0.32)
261 cmyk.BrickRed = cmyk(0, 0.89, 0.94, 0.28)
262 cmyk.Red = cmyk(0, 1, 1, 0)
263 cmyk.OrangeRed = cmyk(0, 1, 0.50, 0)
264 cmyk.RubineRed = cmyk(0, 1, 0.13, 0)
265 cmyk.WildStrawberry = cmyk(0, 0.96, 0.39, 0)
266 cmyk.Salmon = cmyk(0, 0.53, 0.38, 0)
267 cmyk.CarnationPink = cmyk(0, 0.63, 0, 0)
268 cmyk.Magenta = cmyk(0, 1, 0, 0)
269 cmyk.VioletRed = cmyk(0, 0.81, 0, 0)
270 cmyk.Rhodamine = cmyk(0, 0.82, 0, 0)
271 cmyk.Mulberry = cmyk(0.34, 0.90, 0, 0.02)
272 cmyk.RedViolet = cmyk(0.07, 0.90, 0, 0.34)
273 cmyk.Fuchsia = cmyk(0.47, 0.91, 0, 0.08)
274 cmyk.Lavender = cmyk(0, 0.48, 0, 0)
275 cmyk.Thistle = cmyk(0.12, 0.59, 0, 0)
276 cmyk.Orchid = cmyk(0.32, 0.64, 0, 0)
277 cmyk.DarkOrchid = cmyk(0.40, 0.80, 0.20, 0)
278 cmyk.Purple = cmyk(0.45, 0.86, 0, 0)
279 cmyk.Plum = cmyk(0.50, 1, 0, 0)
280 cmyk.Violet = cmyk(0.79, 0.88, 0, 0)
281 cmyk.RoyalPurple = cmyk(0.75, 0.90, 0, 0)
282 cmyk.BlueViolet = cmyk(0.86, 0.91, 0, 0.04)
283 cmyk.Periwinkle = cmyk(0.57, 0.55, 0, 0)
284 cmyk.CadetBlue = cmyk(0.62, 0.57, 0.23, 0)
285 cmyk.CornflowerBlue = cmyk(0.65, 0.13, 0, 0)
286 cmyk.MidnightBlue = cmyk(0.98, 0.13, 0, 0.43)
287 cmyk.NavyBlue = cmyk(0.94, 0.54, 0, 0)
288 cmyk.RoyalBlue = cmyk(1, 0.50, 0, 0)
289 cmyk.Blue = cmyk(1, 1, 0, 0)
290 cmyk.Cerulean = cmyk(0.94, 0.11, 0, 0)
291 cmyk.Cyan = cmyk(1, 0, 0, 0)
292 cmyk.ProcessBlue = cmyk(0.96, 0, 0, 0)
293 cmyk.SkyBlue = cmyk(0.62, 0, 0.12, 0)
294 cmyk.Turquoise = cmyk(0.85, 0, 0.20, 0)
295 cmyk.TealBlue = cmyk(0.86, 0, 0.34, 0.02)
296 cmyk.Aquamarine = cmyk(0.82, 0, 0.30, 0)
297 cmyk.BlueGreen = cmyk(0.85, 0, 0.33, 0)
298 cmyk.Emerald = cmyk(1, 0, 0.50, 0)
299 cmyk.JungleGreen = cmyk(0.99, 0, 0.52, 0)
300 cmyk.SeaGreen = cmyk(0.69, 0, 0.50, 0)
301 cmyk.Green = cmyk(1, 0, 1, 0)
302 cmyk.ForestGreen = cmyk(0.91, 0, 0.88, 0.12)
303 cmyk.PineGreen = cmyk(0.92, 0, 0.59, 0.25)
304 cmyk.LimeGreen = cmyk(0.50, 0, 1, 0)
305 cmyk.YellowGreen = cmyk(0.44, 0, 0.74, 0)
306 cmyk.SpringGreen = cmyk(0.26, 0, 0.76, 0)
307 cmyk.OliveGreen = cmyk(0.64, 0, 0.95, 0.40)
308 cmyk.RawSienna = cmyk(0, 0.72, 1, 0.45)
309 cmyk.Sepia = cmyk(0, 0.83, 1, 0.70)
310 cmyk.Brown = cmyk(0, 0.81, 1, 0.60)
311 cmyk.Tan = cmyk(0.14, 0.42, 0.56, 0)
312 cmyk.Gray = cmyk(0, 0, 0, 0.50)
313 cmyk.Grey = cmyk.Gray
314 cmyk.Black = cmyk(0, 0, 0, 1)
315 cmyk.White = cmyk(0, 0, 0, 0)
316 cmyk.white = cmyk.White
317 cmyk.black = cmyk.Black
320 class palette(color, attr.changeattr):
322 """palette is a collection of two colors for calculating transitions between them"""
324 def __init__(self, mincolor, maxcolor, min=0, max=1):
325 color.__init__(self)
326 if mincolor.__class__ != maxcolor.__class__:
327 raise ValueError
328 self.colorclass = mincolor.__class__
329 self.mincolor = mincolor
330 self.maxcolor = maxcolor
331 self.min = min
332 self.max = max
334 def getcolor(self, index):
335 color = {}
336 for key in self.mincolor.color.keys():
337 color[key] = ((index - self.min) * self.maxcolor.color[key] +
338 (self.max - index) * self.mincolor.color[key]) / float(self.max - self.min)
339 return self.colorclass(**color)
341 def select(self, index, total):
342 if total == 1:
343 return self.mincolor
344 return self.getcolor(index/(total-1.0))
346 def outputPS(self, file, writer, context):
347 self.getcolor(0).outputPS(file, writer, context)
349 def outputPDF(self, file, writer, context):
350 self.getcolor(0).outputPDF(file, writer, context)
353 palette.Gray = palette(gray.white, gray.black)
354 palette.Grey = palette.Gray
355 palette.ReverseGray = palette(gray.black, gray.white)
356 palette.ReverseGrey = palette.ReverseGray
357 palette.RedGreen = palette(rgb.red, rgb.green)
358 palette.RedBlue = palette(rgb.red, rgb.blue)
359 palette.GreenRed = palette(rgb.green, rgb.red)
360 palette.GreenBlue = palette(rgb.green, rgb.blue)
361 palette.BlueRed = palette(rgb.blue, rgb.red)
362 palette.BlueGreen = palette(rgb.blue, rgb.green)
363 palette.RedBlack = palette(rgb.red, rgb.black)
364 palette.BlackRed = palette(rgb.black, rgb.red)
365 palette.RedWhite = palette(rgb.red, rgb.white)
366 palette.WhiteRed = palette(rgb.white, rgb.red)
367 palette.GreenBlack = palette(rgb.green, rgb.black)
368 palette.BlackGreen = palette(rgb.black, rgb.green)
369 palette.GreenWhite = palette(rgb.green, rgb.white)
370 palette.WhiteGreen = palette(rgb.white, rgb.green)
371 palette.BlueBlack = palette(rgb.blue, rgb.black)
372 palette.BlackBlue = palette(rgb.black, rgb.blue)
373 palette.BlueWhite = palette(rgb.blue, rgb.white)
374 palette.WhiteBlue = palette(rgb.white, rgb.blue)
375 palette.Rainbow = palette(hsb(0, 1, 1), hsb(2.0/3.0, 1, 1))
376 palette.ReverseRainbow = palette(hsb(2.0/3.0, 1, 1), hsb(0, 1, 1))
377 palette.Hue = palette(hsb(0, 1, 1), hsb(1, 1, 1))
378 palette.ReverseHue = palette(hsb(1, 1, 1), hsb(0, 1, 1))
381 class PDFextgstate(pdfwriter.PDFobject):
383 def __init__(self, name, extgstate):
384 pdfwriter.PDFobject.__init__(self, "extgstate", name, "ExtGState")
385 self.name = name
386 self.extgstate = extgstate
388 def outputPDF(self, file, writer, registry):
389 file.write("%s\n" % self.extgstate)
392 class transparency(attr.exclusiveattr, style.strokestyle, style.fillstyle):
394 def __init__(self, value):
395 value = 1-value
396 attr.exclusiveattr.__init__(self, transparency)
397 self.name = "Transparency-%f" % value
398 self.extgstate = "<< /Type /ExtGState /CA %f /ca %f >>" % (value, value)
400 def outputPS(self, file, writer, context):
401 raise NotImplementedError("transparency not available in PostScript")
403 def registerPDF(self, registry):
404 registry.add(PDFextgstate(self.name, self.extgstate))
406 def outputPDF(self, file, writer, context):
407 file.write("/%s gs\n" % self.name)