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
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
37 def set(UCRc
=None, UCRm
=None, UCRy
=None, BG
=None):
53 class color(attr
.exclusiveattr
, style
.strokestyle
, style
.fillstyle
):
55 """base class for all colors"""
58 attr
.exclusiveattr
.__init
__(self
, color
)
61 clear
= attr
.clearclass(color
)
68 def __init__(self
, gray
):
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
)
80 file.write("%(gray)f g\n" % self
.color
)
83 return cmyk(0, 0, 0, 1 - self
.color
["gray"])
89 return hsb(0, 0, self
.color
["gray"])
92 return rgb(self
.color
["gray"], self
.color
["gray"], self
.color
["gray"])
94 grey
.black
= grey(0.0)
95 grey
.white
= grey(1.0)
103 def __init__(self
, r
=0.0, g
=0.0, b
=0.0):
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
)
115 file.write("%(r)f %(g)f %(b)f rg\n" % self
.color
)
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
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
))),
128 return grey(0.3*self
.color
["r"] + 0.59*self
.color
["g"] + 0.11*self
.color
["b"])
133 values
= self
.color
.values()
136 r
, g
, b
= self
.color
["r"], self
.color
["g"], self
.color
["b"]
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
)
152 except ZeroDivisionError:
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)
169 def __init__(self
, h
=0.0, s
=0.0, b
=0.0):
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
)
182 return self
.rgb().cmyk()
185 return self
.rgb().grey()
192 h
, s
, b
= self
.color
["h"], self
.color
["s"], self
.color
["b"]
195 m
, n
, k
= 1 - s
, 1 - s
*f
, 1 - s
*(1-f
)
197 return rgb(b
*n
, b
, b
*m
)
199 return rgb(b
*m
, b
, b
*k
)
201 return rgb(b
*m
, b
*n
, b
)
203 return rgb(b
*k
, b
*m
, b
)
205 return rgb(b
, b
*m
, b
*n
)
207 return rgb(b
, b
*k
, b
*m
)
214 def __init__(self
, c
=0.0, m
=0.0, y
=0.0, k
=0.0):
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
)
226 file.write("%(c)f %(m)f %(y)f %(k)f k\n" % self
.color
)
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"]]))
237 return self
.rgb().hsb()
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):
326 if mincolor
.__class
__ != maxcolor
.__class
__:
328 self
.colorclass
= mincolor
.__class
__
329 self
.mincolor
= mincolor
330 self
.maxcolor
= maxcolor
334 def getcolor(self
, index
):
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
):
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")
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
):
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
)