summaryrefslogtreecommitdiffstats
path: root/src/output.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/output.py')
-rw-r--r--src/output.py877
1 files changed, 785 insertions, 92 deletions
diff --git a/src/output.py b/src/output.py
index d0de14a..5df4e7c 100644
--- a/src/output.py
+++ b/src/output.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright © 2014, 2015, 2016, 2017 Mattias Andrée (maandree@kth.se)
+# Copyright © 2014, 2015, 2016, 2017 Mattias Andrée (m@maandree.se)
#
# 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
@@ -17,6 +17,13 @@
# This module is responsible for access to the monitors.
+import math
+
+from colour import *
+from blackbody import *
+
+
+
class Tristate:
'''
Ternary values
@@ -106,7 +113,7 @@ class EDID:
'''
Constructor
- @edid edid:str The EDID in upper case hexadecimal representation
+ @param edid:str The EDID in upper case hexadecimal representation
'''
self.manufacturer_id = None
self.manufacturer_product_code = None
@@ -143,11 +150,14 @@ class EDID:
self.green_chroma = None
self.blue_chroma = None
self.white_chroma = None
+ ## FOR LEGACY {
+ self.__gamma_correction = ...
+ ## }
if edid[:len('00FFFFFFFFFFFF00')] == '00FFFFFFFFFFFF00' or len(edid) % 2 == 1:
return
edid = [int(edid[i * 2 : i * 2 + 2], 16) for i in range(len(edid) // 2)]
- if sum(edid) % 256 != 0 or len(edid[:128]) < 128:
+ if len(edid) < 128 or sum(edid[:128]) % 256 != 0:
return
self.manufacturer_id = [(edid[8] >> 2) & 0x0F, (edid[9] >> 4) | (edid[8] & 1) << 4, edid[9] & 0x0F]
@@ -175,8 +185,8 @@ class EDID:
self.width_mm = edid[21] * 10
self.height_mm = edid[22] * 10
if edid[21] == 0 or edid[22] == 0:
- self.width_mm = self.height_mm = 0
- self.display_gamma = edid[23] / 100 + 1 if edid[23] else None
+ self.width_mm = self.height_mm = None
+ self.display_gamma = None if edid[23] == 255 else edid[23] / 100 + 1
self.dpms_standby_supported = (edid[24] & 128) == 128
self.dpms_suspend_supported = (edid[24] & 64) == 64
self.dpms_active_off_supported = (edid[24] & 32) == 32
@@ -211,6 +221,69 @@ class EDID:
self.white_chroma = (wx / 1024, wy / 1024)
# There are also mode lines and maybe extensions, but yeah...
+
+ ## FOR LEGACY {
+ @property
+ def widthmm(self):
+ if not EDID.warned_widthmm:
+ EDID.warned_widthmm = True
+ print('EDID.widthmm is deprecated, use EDID.width_mm instead', file = sys.stderr)
+ return self.width_mm
+ @widthmm.setter
+ def widthmm(self, value):
+ if not EDID.warned_widthmm:
+ EDID.warned_widthmm = True
+ print('EDID.widthmm is deprecated, use EDID.width_mm instead', file = sys.stderr)
+ self.width_mm = value
+ @property
+ def heightmm(self):
+ if not EDID.warned_heightmm:
+ EDID.warned_heightmm = True
+ print('EDID.heightmm is deprecated, use EDID.height_mm instead', file = sys.stderr)
+ return self.height_mm
+ @heightmm.setter
+ def heightmm(self, value):
+ if not EDID.warned_heightmm:
+ EDID.warned_heightmm = True
+ print('EDID.heightmm is deprecated, use EDID.height_mm instead', file = sys.stderr)
+ self.height_mm = value
+ @property
+ def gamma(self):
+ if not EDID.warned_gamma:
+ EDID.warned_gamma = True
+ print('EDID.gamma is deprecated, use EDID.display_gamma instead', file = sys.stderr)
+ return self.display_gamma
+ @gamma.setter
+ def gamma(self, value):
+ if not EDID.warned_gamma:
+ EDID.warned_gamma = True
+ print('EDID.gamma is deprecated, use EDID.display_gamma instead', file = sys.stderr)
+ self.display_gamma = value
+ @property
+ def gamma_correction(self):
+ if not EDID.warned_gamma_correction:
+ EDID.warned_gamma_correction = True
+ print('EDID.gamma_correction is deprecated', file = sys.stderr)
+ if self.__gamma_correction is ...:
+ if self.display_gamma is None:
+ self.__gamma_correction = None
+ else:
+ self.__gamma_correction = self.display_gamma / 2.2
+ return self.__gamma_correction
+ @gamma_correction.setter
+ def gamma_correction(self, value):
+ if not EDID.warned_gamma_correction:
+ EDID.warned_gamma_correction = True
+ print('EDID.gamma_correction is deprecated', file = sys.stderr)
+ self.__gamma_correction = value
+
+EDID.warned_widthmm = False
+EDID.warned_heightmm = False
+EDID.warned_gamma = False
+EDID.warned_gamma_correction = False
+## }
+
+
class MultiCRTC:
'''
A group of CRTC:s organised for efficient gamma ramp adjustments
@@ -231,6 +304,7 @@ class MultiCRTC:
for crtc in crtcs:
self.add(crtc)
+
def add(self, crtc):
'''
Add a CRTC
@@ -271,6 +345,7 @@ class MultiCRTC:
subsubfound.append(crtc)
+
def make_ramps(self, depth = -2):
'''
Create a gamma-ramp trio where each ramp is as large as the
@@ -291,6 +366,7 @@ class MultiCRTC:
size[2] = max(size[2], crtc.blue_gamma_size)
return Ramps(None, depth = depth, size = size)
+
def set_gamma(self, ramps, priority = None, rule = None, lifespan = 1):
'''
Set the gamma ramps on all CRTC:s in the group
@@ -319,7 +395,7 @@ class MultiCRTC:
refsize = (ref.red_gamma_size, ref.green_gamma_size, ref.blue_gamma_size)
if refsize == (len(ramps.red), len(ramps.green), len(ramps.blue)):
ramps_size = ramps
- else
+ else:
ramps_size = Ramps.copy(ramps, refcrtc.depth, refsize)
for sublayer in layer:
ref = sublayer[0][0]
@@ -333,6 +409,7 @@ class MultiCRTC:
for crtc in subsublayer:
ramps_backend = crtc.set_gamma(ramps_backend, priority, rule, lifespan)
+
class CRTC:
'''
A CRTC
@@ -340,6 +417,7 @@ class CRTC:
@function restore:(self)?→void Restore the CLUT:s to the (configured) system
defaults, `None` if not supported
+ @variable screen:Screen The screen
@variable edid:str? The EDID in upper case hexadecimal representation
@variable red_gamma_size:int? The number of stops in the red gamma ramp
@variable green_gamma_size:int? The number of stops in the green gamma ramp
@@ -477,6 +555,7 @@ class CRTC:
self.blue_chroma = None
self.white_chroma = None
+
def make_ramps(self, depth = None):
'''
Create gamma ramps with the same size as the CRTC expects
@@ -491,6 +570,7 @@ class CRTC:
'''
return Ramps(self, depth = depth)
+
@property
def edid_data(self):
'''
@@ -502,12 +582,16 @@ class CRTC:
self.__edid_data = None if self.edid is None else EDID(self.edid)
return self.__edid_data
+
class Screen:
'''
A screen or graphics card
- @function restore:(self)?→void Restore the CLUT:s to the (configured) system
- defaults, `None` if not supported
+ @function restore:(self)?→void Restore the CLUT:s to the (configured) system defaults,
+ `None` if not supported
+
+ @variable display:Display The display
+ @variable crtcs:list<LibgammaCRTC> The CRTC:s in the screen
'''
def __len__(self):
'''
@@ -517,6 +601,7 @@ class Screen:
'''
return len(self.crtcs)
+
def __getitem__(self, indices):
'''
Get CRTC:s in the screen
@@ -526,6 +611,7 @@ class Screen:
'''
return self.crtcs[indices]
+
def __iter__(self):
'''
Iterator of the screen's CRTC:s
@@ -535,12 +621,17 @@ class Screen:
for value in self[:]:
yield value
+
class Display:
'''
A display
- @function restore:(self)?→void Restore the CLUT:s to the (configured) system
- defaults, `None` if not supported
+ @function restore:(self)?→void Restore the CLUT:s to the (configured) system defaults,
+ `None` if not supported
+
+ @variable screens:list<LibgammaScreen> The screens in the display
+ @variable crtcs:list<LibgammaCRTC> The CRTC:s in the display
+ @variable cooperative:bool Whether the adjustment method supports cooperative gamma
'''
def __len__(self):
'''
@@ -550,6 +641,7 @@ class Display:
'''
return len(self.crtcs)
+
def __getitem__(self, indices):
'''
Get screens in the display
@@ -559,6 +651,7 @@ class Display:
'''
return self.crtcs[indices]
+
def __iter__(self):
'''
Iterator of the display's screens
@@ -568,7 +661,8 @@ class Display:
for value in self[:]:
yield value
-class Ramps: ## TODO adjustments
+
+class Ramps:
'''
Gamma ramps
@@ -580,6 +674,7 @@ class Ramps: ## TODO adjustments
32-bit integers, 64 for unsigned 64-bit integers,
-1 for single-precision floating-point values, and
-2 for double-precision floating-point values
+ @variable maximum:float The largest stop value
'''
def __init__(self, crtc, depth = None, size = None):
'''
@@ -589,32 +684,34 @@ class Ramps: ## TODO adjustments
only be `None` if neither `depth` nor
`size` is `None`
@param depth:int? The gamma depth, 8 for unsigned 8-bit integers,
- 16 for unsigned 16-bit integers, 32 for unsigned
- 32-bit integers, 64 for unsigned 64-bit integers,
- -1 for single-precision floating-point values,
- -2 for double-precision floating-point values, and
- `None` for the gamma depth the CRTC expects
+ 16 for unsigned 16-bit integers, 32 for unsigned
+ 32-bit integers, 64 for unsigned 64-bit integers,
+ -1 for single-precision floating-point values,
+ -2 for double-precision floating-point values, and
+ `None` for the gamma depth the CRTC expects
@param size:int|(red:int, green:int, blue:int)?
- The size of the ramps, either an integer of the size that
- is applied to all three channels, three integers with
- the size of each channel, or `None` for the sizes the
- CRTC expects
+ The size of the ramps, either an integer of the size that
+ is applied to all three channels, three integers with
+ the size of each channel, or `None` for the sizes the
+ CRTC expects
'''
if depth is None:
depth = crtc.depth
if size is not None and isinstance(size, int):
size = (size, size, size)
self.depth = depth
- def make_ramp(depth, size):
- if depth > 0:
- m = 1 << (depth - 1)
- return [int(x * m / (size - 1) + 0.5) for x in range(size)]
- else:
+ self.maximum = 1 if depth < 0 else (1 << depth) - 1
+ if depth > 0:
+ def make_ramp(depth, size):
+ return [int(x * self.maximum / (size - 1) + 0.5) for x in range(size)]
+ else:
+ def make_ramp(depth, size):
return [x / (size - 1) for x in range(size)]
self.red = make_ramp(self.depth, crtc.red_gamma_size if size is None else size[0])
self.green = make_ramp(self.depth, crtc.green_gamma_size if size is None else size[1])
self.blue = make_ramp(self.depth, crtc.blue_gamma_size if size is None else size[2])
+
def copy(self, depth = None, size = None, interpolation = None):
'''
Create a copy, optionally with a new depth or size
@@ -645,19 +742,601 @@ class Ramps: ## TODO adjustments
pass
elif interpolation is None:
import interpolation as interpol
- ramps = interpol.linearly_interpolate_ramp(*ramps)
+ ramps = interpol.linearly_interpolate_ramp(*ramps, size = size)
else:
- ramps = interpolation(*ramps)
+ ramps = interpolation(*ramps, size = size)
r.red[:] = ramps[0]
r.green[:] = ramps[1]
r.blue[:] = ramps[2]
- old_max = 1 << (self.depth - 1) if self.depth > 0 else 1
- new_max = 1 << (depth - 1) if depth > 0 else 1
- if new_max != old_max:
+ if r.maximum != self.maximum:
for ramp in (r.red, r.green, r.blue):
for i in range(len(ramp)):
- ramp[i] = ramp[i] * new_max / old_max
+ ramp[i] = ramp[i] * r.maximum / self.maximum
return r
+
+
+ def __str__(self, compact = False):
+ '''
+ Create a string of the ramps that is useful for debugging
+
+ @param compact:bool Whether to apply run-length compression when suitable
+ @return :str A printable string
+ '''
+ if not compact:
+ return '%s\n%s\n%s' % (repr(red), repr(green), repr(blue))
+ rgb = ([], [], [])
+ for r, w in zip((self.red, self.green, self.blue), rgb):
+ last, count = None, 0
+ for value in r:
+ if self.depth > 0:
+ value = int(value + 0.5)
+ if value == last:
+ count += 1
+ else:
+ if last is not None:
+ if count > 1:
+ w.append(repr(last))
+ else:
+ w.append('%s {%i}' % (repr(last), count))
+ last = value
+ count = 1
+ if last is not None:
+ if count > 1:
+ w.append(repr(last))
+ else:
+ w.append('%s {%i}' % (repr(last), count))
+ return '[%s]\n[%s]\n[%s]' % (', '.join(rgb[0]), ', '.join(rgb[1]), ', '.join(rgb[2]))
+
+
+ def __bool(self, r, g, b):
+ if g is ...: g = r
+ if b is ...: b = g
+ ret = []
+ if r: ret.append(self.red)
+ if g: ret.append(self.green)
+ if b: ret.append(self.blue)
+ return ret
+
+
+ def __datum(self, r, g, b):
+ if g is ...: g = r
+ if b is ...: b = g
+ ret = []
+ if r is not None: ret.append((self.red, r))
+ if g is not None: ret.append((self.green, g))
+ if b is not None: ret.append((self.blue, b))
+ return ret
+
+
+ def temperature(self, temperature, algorithm):
+ '''
+ Change colour temperature according to the CIE illuminant series D using CIE sRBG
+
+ @param temperature:float|str The blackbody temperature in kelvins, or a name
+ @param algorithm:(float)→(float, float, float) Algorithm for calculating a white point, for example `cmf_10deg`
+ '''
+ self.rgb_temperature(temperature, algorithm)
+
+
+ def rgb_temperature(self, temperature, algorithm):
+ '''
+ Change colour temperature according to the CIE illuminant series D using CIE sRBG
+
+ @param temperature:float|str The blackbody temperature in kelvins, or a name
+ @param algorithm:(float)→(float, float, float) Algorithm for calculating a white point, for example `cmf_10deg`
+ '''
+ # Resolve colour temperature name
+ temperature = kelvins(temperature)
+ # Do nothing if the temperature is neutral
+ if temperature == 6500: return
+ # Otherwise manipulate the colour curves
+ self.rgb_brightness(*(algorithm(temperature)))
+
+
+ def cie_temperature(self, temperature, algorithm):
+ '''
+ Change colour temperature according to the CIE illuminant series D using CIE xyY
+
+ @param temperature:float|str The blackbody temperature in kelvins, or a name
+ @param algorithm:(float)→(float, float, float) Algorithm for calculating a white point, for example `cmf_10deg`
+ '''
+ # Resolve colour temperature name
+ temperature = kelvins(temperature)
+ # Do nothing if the temperature is neutral
+ if temperature == 6500: return
+ # Otherwise manipulate the colour curves
+ self.cie_brightness(*(algorithm(temperature)))
+
+
+ def rgb_contrast(self, r, g = ..., b = ...):
+ '''
+ Apply contrast correction on the colour curves using sRGB
+
+ In this context, contrast is a measure of difference between the whitepoint and blackpoint,
+ if the difference is 0 than they are both grey
+
+ @param r:float? The contrast parameter for the red curve
+ @param g:float|...? The contrast parameter for the green curve, defaults to `r` if `...`
+ @param b:float|...? The contrast parameter for the blue curve, defaults to `g` if `...`
+ '''
+ half = self.maximum / 2
+ for (curve, level) in self.__value(r, g, b):
+ if not level == 1.0:
+ curve[:] = [(y - half) * level + half for y in curve]
+
+
+ def cie_contrast(self, r, g = ..., b = ...):
+ '''
+ Apply contrast correction on the colour curves using CIE xyY
+
+ In this context, contrast is a measure of difference between the whitepoint and blackpoint,
+ if the difference is 0 than they are both grey
+
+ @param r:float? The contrast parameter for the red curve
+ @param g:float|...? The contrast parameter for the green curve, defaults to `r` if `...`
+ @param b:float|...? The contrast parameter for the blue curve, defaults to `g` if `...`
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Check if we can reduce the overhead, we can if the adjustments are identical
+ same = r == g == b
+ # Check we need to do any adjustment
+ if (not same) or (not r == 1.0):
+ if same:
+ if r is None:
+ return
+ # Manipulate all curves in one step if their adjustments are identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate illumination and convert back to sRGB
+ (r_, g_, b_) = ciexyy_to_srgb(x, y, (Y - 0.5) * r + 0.5)
+ if r: self.red[i] = r_ * self.maximum
+ if g: self.green[i] = g_ * self.maximum
+ if b: self.blue[i] = b_ * self.maximum
+ else:
+ # Manipulate all curves individually if their adjustments are not identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate illumination and convert back to sRGB
+ if r: self.red[i] = ciexyy_to_srgb(x, y, (Y - 0.5) * r + 0.5)[0] * self.maximum
+ if g: self.green[i] = ciexyy_to_srgb(x, y, (Y - 0.5) * g + 0.5)[1] * self.maximum
+ if b: self.blue[i] = ciexyy_to_srgb(x, y, (Y - 0.5) * b + 0.5)[2] * self.maximum
+
+
+ def rgb_brightness(self, r, g = ..., b = ...):
+ '''
+ Apply brightness correction on the colour curves using sRGB
+
+ In this context, brightness is a measure of the whiteness of the whitepoint
+
+ @param r:float? The brightness parameter for the red curve
+ @param g:float|...? The brightness parameter for the green curve, defaults to `r` if `...`
+ @param b:float|...? The brightness parameter for the blue curve, defaults to `g` if `...`
+ '''
+ for (curve, level) in curves(r, g, b):
+ if not level == 1.0:
+ curve[:] = [y * level for y in curve]
+
+
+ def cie_brightness(self, r, g = ..., b = ...):
+ '''
+ Apply brightness correction on the colour curves using CIE xyY
+
+ In this context, brightness is a measure of the whiteness of the whitepoint
+
+ @param r:float? The brightness parameter for the red curve
+ @param g:float|...? The brightness parameter for the green curve, defaults to `r` if `...`
+ @param b:float|...? The brightness parameter for the blue curve, defaults to `g` if `...`
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Check if we can reduce the overhead, we can if the adjustments are identical
+ same = r == g == b
+ # Check we need to do any adjustment
+ if (not same) or (not r == 1.0):
+ if same:
+ if r is None:
+ return
+ # Manipulate all curves in one step if their adjustments are identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ (r_, g_, b_) = ciexyy_to_srgb(x, y, Y * r)
+ if r: self.red[i] = r_ * self.maximum
+ if g: self.green[i] = g_ * self.maximum
+ if b: self.blue[i] = b_ * self.maximum
+ else:
+ # Manipulate all curves individually if their adjustments are not identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate illumination and convert back to sRGB
+ if r: self.red[i] = ciexyy_to_srgb(x, y, Y * r)[0] * self.maximum
+ if g: self.green[i] = ciexyy_to_srgb(x, y, Y * g)[1] * self.maximum
+ if b: self.blue[i] = ciexyy_to_srgb(x, y, Y * b)[2] * self.maximum
+
+
+ def linearise(self, r = True, g = ..., b = ...):
+ '''
+ Convert the curves from formatted in standard RGB to linear RGB
+
+ @param r:bool Whether to convert the red colour curve
+ @param g:bool|... Whether to convert the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to convert the blue colour curve, defaults to `g` if `...`
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Convert colour space
+ if not r and not g and not b:
+ return
+ for i in range(i_size):
+ (r_, g_, b_) = standard_to_linear(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ if r: self.red[i] = r_ * self.maximum
+ if g: self.green[i] = g_ * self.maximum
+ if b: self.blue[i] = b_ * self.maximum
+
+
+ def standardise(self, r = True, g = ..., b = ...):
+ '''
+ Convert the curves from formatted in linear RGB to standard RGB
+
+ @param r:bool Whether to convert the red colour curve
+ @param g:bool|... Whether to convert the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to convert the blue colour curve, defaults to `g` if `...`
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Convert colour space
+ if not r and not g and not b:
+ return
+ for i in range(i_size):
+ (r_, g_, b_) = linear_to_standard(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ if r: self.red[i] = r_ * self.maximum
+ if g: self.green[i] = g_ * self.maximum
+ if b: self.blue[i] = b_ * self.maximum
+
+
+ def gamma(self, r, g = ..., b = ...):
+ '''
+ Apply gamma correction on the colour curves
+
+ @param r:float? The gamma parameter for the red colour curve
+ @param g:float|...? The gamma parameter for the green colour curve, defaults to `r` if `...`
+ @param b:float|...? The gamma parameter for the blue colour curve, defaults to `g` if `...`
+ '''
+ for (curve, level) in self.__value(r, g, b):
+ if not level == 1.0:
+ curve[:] = [(y / self.maximum) ** (1 / level) * self.maximum for y in curve]
+
+
+ def negative(self, r = True, g = ..., b = ...):
+ '''
+ Reverse the colour curves (negative image with gamma preservation)
+
+ @param r:bool Whether to invert the red colour curve
+ @param g:bool|... Whether to invert the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to invert the blue colour curve, defaults to `g` if `...`
+ '''
+ for curve in self.__bool(r, g, b):
+ curve[:] = reversed(curve)
+
+
+ def rgb_invert(self, r = True, g = ..., b = ...):
+ '''
+ Invert the colour curves (negative image with gamma invertion), using sRGB
+
+ @param r:bool Whether to invert the red colour curve
+ @param g:bool|... Whether to invert the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to invert the blue colour curve, defaults to `g` if `...`
+ '''
+ for curve in self.__bool(r, g, b):
+ curve[:] = [self.maximum - y for y in curve]
+
+
+ def cie_invert(self, r = True, g = ..., b = ...):
+ '''
+ Invert the colour curves (negative image with gamma invertion), using CIE xyY
+
+ @param r:bool Whether to invert the red colour curve
+ @param g:bool|... Whether to invert the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to invert the blue colour curve, defaults to `g` if `...`
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Manipulate the colour curves if any curve should be manipulated
+ if r or g or b:
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Invert illumination and convert to back sRGB
+ (r_, g_, b_) = ciexyy_to_srgb(x, y, 1 - Y)
+ # Apply the new values on the selected channels
+ if r: self.red[i] = r_ * self.maximum
+ if g: self.green[i] = g_ * self.maximum
+ if b: self.blue[i] = b_ * self.maximum
+
+
+ def sigmoid(self, r, g = ..., b = ...):
+ '''
+ Apply S-curve correction on the colour curves.
+ This is intended for fine tuning LCD monitors,
+ 4.5 is good value start start testing at.
+ You would probably like to use rgb_limits before
+ this to adjust the black point as that is the
+ only way to adjust the black point on many LCD
+ monitors.
+
+ @param r:float? The sigmoid parameter for the red colour curve
+ @param g:float|...? The sigmoid parameter for the green colour curve, defaults to `r` if `...`
+ @param b:float|...? The sigmoid parameter for the blue colour curve, defaults to `g` if `...`
+ '''
+ for (curve, level) in self.__value(r, g, b):
+ for i in range(i_size):
+ try:
+ curve[i] = (0.5 - math.log(self.maximum / curve[i] - 1) / level) * self.maximum
+ except:
+ # Corner cases:
+ # curve[i] = 0 → 0 -- Division by zero
+ # curve[i] = self.maximum → self.maximum -- Logarithm of zero
+ pass
+
+
+ def rgb_limits(self, r_min, r_max, g_min = ..., g_max = ..., b_min = ..., b_max = ...):
+ '''
+ Changes the black point and the white point, using sRGB
+
+ @param r_min:float The red component value of the black point
+ @param r_max:float The red component value of the white point
+ @param g_min:float|... The green component value of the black point, defaults to `r_min`
+ @param g_max:float|... The green component value of the white point, defaults to `r_max`
+ @param b_min:float|... The blue component value of the black point, defaults to `g_min`
+ @param b_max:float|... The blue component value of the white point, defaults to `g_max`
+ '''
+ # Handle overloading
+ if g_min is ...: g_min = r_min
+ if g_max is ...: g_max = r_max
+ if b_min is ...: b_min = g_min
+ if b_max is ...: b_max = g_max
+ # Manipulate the colour curves
+ for (curve, (level_min, level_max)) in self.__values((r_min, r_max), (g_min, g_max), (b_min, b_max)):
+ # But not if the adjustments are neutral
+ if (level_min != 0) or (level_max != self.maximum):
+ curve[:] = [y * (level_max - level_min) + level_min for y in curve]
+
+
+ def cie_limits(self, r_min, r_max, g_min = ..., g_max = ..., b_min = ..., b_max = ...):
+ '''
+ Changes the black point and the white point, using CIE xyY
+
+ @param r_min:float The red component value of the black point
+ @param r_max:float The red component value of the white point
+ @param g_min:float|... The green component value of the black point, defaults to `r_min`
+ @param g_max:float|... The green component value of the white point, defaults to `r_max`
+ @param b_min:float|... The blue component value of the black point, defaults to `g_min`
+ @param b_max:float|... The blue component value of the white point, defaults to `g_max`
+ '''
+ # Handle overloading
+ if g_min is ...: g_min = r_min
+ if g_max is ...: g_max = r_max
+ if b_min is ...: b_min = g_min
+ if b_max is ...: b_max = g_max
+ # Check if we can reduce the overhead, we can if the adjustments are identical
+ same = (r_min == g_min == b_min) and (r_max == g_max == b_max)
+ # Check we need to do any adjustment
+ if (not same) or (not r_min == 0) or (not r_max == self.maximum):
+ if same:
+ # Manipulate all curves in one step if their adjustments are identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate illumination
+ Y = Y * (r_max - r_min) + r_min
+ # Convert back to sRGB
+ (r_, g_, b_) = ciexyy_to_srgb(x, y, Y)
+ self.red[i] = r_ * self.maximum
+ self.green[i] = g_ * self.maximum
+ self.blue[i] = b_ * self.maximum
+ else:
+ # Manipulate all curves individually if their adjustments are not identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate illumination and convert back to sRGB
+ self.red[i] = ciexyy_to_srgb(x, y, Y * (r_max - r_min) + r_min)[0] * self.maximum
+ self.green[i] = ciexyy_to_srgb(x, y, Y * (g_max - g_min) + g_min)[1] * self.maximum
+ self.blue[i] = ciexyy_to_srgb(x, y, Y * (b_max - b_min) + b_min)[2] * self.maximum
+
+
+ def manipulate(self, r, g = ..., b = ...):
+ '''
+ Manipulate the colour curves using a (lambda) function
+
+ @param r:(float)?→float Function to manipulate the red colour curve
+ @param g:(float)?→float|... Function to manipulate the green colour curve, defaults to `r` if `...`
+ @param b:(float)?→float|... Function to manipulate the blue colour curve, defaults to `g` if `...`
+
+ `None` means that nothing is done for that subpixel
+
+ The lambda functions thats a colour value and maps it to a new colour value.
+ For example, if the red value 0.5 is already mapped to 0.25, then if the function
+ maps 0.25 to 0.5, the red value 0.5 will revert back to being mapped to 0.5.
+ '''
+ for (curve, f) in self.__values(r, g, b):
+ curve[:] = [f(y) for y in curve]
+
+
+ def cie_manipulate(self, r, g = ..., b = ...):
+ '''
+ Manipulate the colour curves using a (lambda) function on the CIE xyY colour space
+
+ @param r:(float)?→float Function to manipulate the red colour curve
+ @param g:(float)?→float|... Function to manipulate the green colour curve, defaults to `r` if `...`
+ @param b:(float)?→float|... Function to manipulate the blue colour curve, defaults to `g` if `...`
+
+ `None` means that nothing is done for that subpixel
+
+ The lambda functions thats a colour value and maps it to a new illumination value.
+ For example, if the value 0.5 is already mapped to 0.25, then if the function
+ maps 0.25 to 0.5, the value 0.5 will revert back to being mapped to 0.5.
+ '''
+ # Handle overloading
+ if g is ...: g = r
+ if b is ...: b = g
+ # Check if we can reduce the overhead, we can if the adjustments are identical
+ same = (r is g) and (g is b)
+ if same:
+ if r is None:
+ return
+ # Manipulate all curves in one step if their adjustments are identical
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate and convert by to sRGB
+ (r_, g_, b_) = ciexyy_to_srgb(x, y, r(Y))
+ self.red[i] = r_ * self.maximum
+ self.green[i] = g_ * self.maximum
+ self.blue[i] = b_ * self.maximum
+ elif any(f is not None for f in (r, g, b)):
+ # Manipulate all curves individually if their adjustments are not identical
+ # if we are given a function for any curve
+ for i in range(i_size):
+ # Convert to CIE xyY
+ (x, y, Y) = srgb_to_ciexyy(self.red[i] / self.maximum,
+ self.green[i] / self.maximum,
+ self.blue[i] / self.maximum)
+ # Manipulate and convert by to sRGB for selected channels individually
+ if r is not None: self.red[i] = ciexyy_to_srgb(x, y, r(Y))[0] * self.maximum
+ if g is not None: self.green[i] = ciexyy_to_srgb(x, y, g(Y))[1] * self.maximum
+ if b is not None: self.blue[i] = ciexyy_to_srgb(x, y, b(Y))[2] * self.maximum
+
+
+ def lower_resolution(self, rx_colours = None, ry_colours = None, gx_colours = ..., gy_colours = ..., bx_colours = ..., by_colours = ...):
+ '''
+ Emulates low colour resolution
+
+ @param rx_colours:int? The number of colours to emulate on the red encoding axis
+ @param ry_colours:int? The number of colours to emulate on the red output axis
+ @param gx_colours:int|...? The number of colours to emulate on the green encoding axis, `rx_colours` if `...`
+ @param gy_colours:int|...? The number of colours to emulate on the green output axis, `ry_colours` if `...`
+ @param bx_colours:int|...? The number of colours to emulate on the blue encoding axis, `gx_colours` if `...`
+ @param by_colours:int|...? The number of colours to emulate on the blue output axis, `gy_colours` if `...`
+
+ Where `None` is used the default value will be used, for *x_colours:es that is `i_size`,
+ and for *y_colours:es that is `o_size`
+ '''
+ # Handle overloading
+ if gx_colours is ...: gx_colours = rx_colours
+ if gy_colours is ...: gy_colours = ry_colours
+ if bx_colours is ...: bx_colours = gx_colours
+ if by_colours is ...: by_colours = gy_colours
+ # Select default values where default is requested
+ if rx_colours is None: rx_colours = i_size
+ if ry_colours is None: ry_colours = o_size
+ if gx_colours is None: gx_colours = i_size
+ if gy_colours is None: gy_colours = o_size
+ if bx_colours is None: bx_colours = i_size
+ if by_colours is None: by_colours = o_size
+ # Combine pair X and Y parameters for each channel
+ r_colours = (rx_colours, ry_colours)
+ g_colours = (gx_colours, gy_colours)
+ b_colours = (bx_colours, by_colours)
+ # Manipulate colour curves
+ for i_curve, (x_colours, y_colours) in self.__values(r_colours, g_colours, b_colours):
+ # But not if adjustment is neutral
+ if (x_colours == i_size) and (y_colours == o_size):
+ continue
+ o_curve = [0] * i_size
+ x_, y_, i_ = x_colours - 1, y_colours - 1, i_size - 1
+ for i in range(i_size):
+ # Scale encoding
+ x = int(i * x_colours / i_size)
+ x = int(x * i_ / x_)
+ # Scale output
+ y = int(i_curve[x] / self.maximum * y_ + 0.5)
+ o_curve[i] = y / y_ * self.maximum
+ i_curve[:] = o_curve
+
+
+ def start_over(self, r = True, g = ..., b = ...):
+ '''
+ Reverts the curves to identity mappings
+
+ @param r:bool Whether to reset the red colour curve
+ @param g:bool|... Whether to reset the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to reset the blue colour curve, defaults to `g` if `...`
+ '''
+ if self.depth > 0:
+ def make_ramp(size):
+ return [int(x * self.maximum / (size - 1) + 0.5) for x in range(size)]
+ else:
+ def make_ramp(size):
+ return [x / (size - 1) for x in range(size)]
+ for curve in self.__bool(r, g, b):
+ curve[:] = make_ramp(len(curve))
+
+
+ def clip_below(self, r = True, g = ..., b = ...):
+ '''
+ Clip all values below the actual minimum
+
+ @param r:bool Whether to clip the red colour curve
+ @param g:bool|... Whether to clip the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to clip the blue colour curve, defaults to `g` if `...`
+ '''
+ for curve in self.__bool(r, g, b):
+ curve[:] = [max(0, y) for y in curve]
+
+
+ def clip_above(self, r = True, g = ..., b = ...):
+ '''
+ Clip all values above the actual maximum
+
+ @param r:bool Whether to clip the red colour curve
+ @param g:bool|... Whether to clip the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to clip the blue colour curve, defaults to `g` if `...`
+ '''
+ for curve in self.__bool(r, g, b):
+ curve[:] = [min(y, self.maximum) for y in curve]
+
+
+ def clip(self, r = True, g = ..., b = ...):
+ '''
+ Clip all values below the actual minimum and above the actual maximum
+
+ @param r:bool Whether to clip the red colour curve
+ @param g:bool|... Whether to clip the green colour curve, defaults to `r` if `...`
+ @param b:bool|... Whether to clip the blue colour curve, defaults to `g` if `...`
+ '''
+ for curve in self.__bool(r, g, b):
+ curve[:] = [min(max(0, y), self.maximum) for y in curve]
+
class LibgammaCRTC(CRTC):
'''
@@ -674,39 +1353,40 @@ class LibgammaCRTC(CRTC):
'''
import libgamma
CRTC.__init__(self)
- self.crtc = libgamma.CRTC(screen, crtc)
+ self.crtc = libgamma.CRTC(screen.screen, crtc)
+ self.screen = screen
if screen.display.caps.crtc_restore:
self.restore = self.crtc.restore
else:
self.restore = None
- info = libgamma.information(~0)[0]
+ info = self.crtc.information(~0)[0]
connector_types = {
- libgamma.LIBGAMMA_CONNECTOR_TYPE_9PinDIN = '9PinDIN',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_Component = 'Component',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_Composite = 'Composite',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DSI = 'DSI',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DVI = 'DVI',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DVIA = 'DVIA',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DVID = 'DVID',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DVII = 'DVII',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_DisplayPort = 'DisplayPort',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMI = 'HDMI',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMIA = 'HDMIA',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMIB = 'HDMIB',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_LFP = 'LFP',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_LVDS = 'LVDS',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_SVIDEO = 'SVIDEO',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_TV = 'TV',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_VGA = 'VGA',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_VIRTUAL = 'VIRTUAL',
- libgamma.LIBGAMMA_CONNECTOR_TYPE_eDP = 'eDP'
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_9PinDIN : '9PinDIN',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_Component : 'Component',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_Composite : 'Composite',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DSI : 'DSI',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DVI : 'DVI',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DVIA : 'DVIA',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DVID : 'DVID',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DVII : 'DVII',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_DisplayPort : 'DisplayPort',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMI : 'HDMI',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMIA : 'HDMIA',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_HDMIB : 'HDMIB',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_LFP : 'LFP',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_LVDS : 'LVDS',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_SVIDEO : 'SVIDEO',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_TV : 'TV',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_VGA : 'VGA',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_VIRTUAL : 'VIRTUAL',
+ libgamma.LIBGAMMA_CONNECTOR_TYPE_eDP : 'eDP'
}
subpixel_orders = {
- libgamma.LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_BGR = 'BGR',
- libgamma.LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_RGB = 'RGB',
- libgamma.LIBGAMMA_SUBPIXEL_ORDER_NONE = 'None',
- libgamma.LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_BGR = 'vBGR',
- libgamma.LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_RGB = 'vRGB'
+ libgamma.LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_BGR : 'BGR',
+ libgamma.LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_RGB : 'RGB',
+ libgamma.LIBGAMMA_SUBPIXEL_ORDER_NONE : 'None',
+ libgamma.LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_BGR : 'vBGR',
+ libgamma.LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_RGB : 'vRGB'
}
self.edid = None if info.edid_error else libgamma.behex_edid_uppercase(info.edid)
self.width_mm = None if info.width_mm_error else info.width_mm
@@ -728,6 +1408,7 @@ class LibgammaCRTC(CRTC):
self.ramps = libgamma.GammaRamps(self.red_gamma_size, self.green_gamma_size,
self.blue_gamma_size, depth = self.gamma_depth)
+
@property
def backend(self):
'''
@@ -738,6 +1419,7 @@ class LibgammaCRTC(CRTC):
'''
return 'libgamma'
+
def get_gamma(self, low_priority = None, high_priority = None, coalesce = True):
'''
Get the gamma ramps on the CRTC or the table of applied adjustments
@@ -761,9 +1443,10 @@ class LibgammaCRTC(CRTC):
'''
if low_priority is not None or high_priority is not None or not coalesce:
raise Exception('Cooperative gamma is not supported')
- self.crtc.get_gamma(self.ramps):
+ self.crtc.get_gamma(self.ramps)
return Ramps.copy(self.ramps)
+
def set_gamma(self, ramps, priority = None, rule = None, lifespan = 1):
'''
Set the gamma ramps on the CRTC
@@ -785,17 +1468,17 @@ class LibgammaCRTC(CRTC):
if priority is not None or rule is not None or lifespan != 1:
raise Exception('Cooperative gamma is not supported')
if ramps is self.ramps:
- self.crtc.set_gamma(ramps):
+ self.crtc.set_gamma(ramps)
return ramps
- match = ramps.gamma == self.gamma_depth:
- match = match and len(ramps.red) == self.red_gamma_size:
- match = match and len(ramps.green) == self.green_gamma_size:
- match = match and len(ramps.blue) == self.blue_gamma_size:
+ match = ramps.depth == self.gamma_depth
+ match = match and len(ramps.red) == self.red_gamma_size
+ match = match and len(ramps.green) == self.green_gamma_size
+ match = match and len(ramps.blue) == self.blue_gamma_size
if not match:
- ramps = Ramps.copy(ramp, self.gamma_depth,
+ ramps = Ramps.copy(ramps, self.gamma_depth,
(self.red_gamma_size, self.green_gamma_size, self.blue_gamma_size))
if isinstance(ramps, libgamma.GammaRamps):
- self.crtc.set_gamma(ramps):
+ self.crtc.set_gamma(ramps)
return
for i in range(len(ramps.red)):
self.ramps.red[i] = ramps.red[i]
@@ -806,11 +1489,10 @@ class LibgammaCRTC(CRTC):
self.crtc.set_gamma(self.ramps)
return self.ramps
+
class LibgammaScreen(Screen):
'''
A screen (or graphics card) using the libgamma backend
-
- @variable crtcs:list<LibgammaCRTC> The CRTC:s in the screen
'''
def __init__(self, display, screen, crtcs = None):
'''
@@ -823,7 +1505,8 @@ class LibgammaScreen(Screen):
@param crtcs:set<int|str>? List of CRTC:s to include, `None` for all
'''
import libgamma
- self.screen = libgamma.Partition(display, screen)
+ self.screen = libgamma.Partition(display.display, screen)
+ self.display = display
if display.caps.partition_restore:
self.restore = self.screen.restore
elif display.caps.crtc_restore:
@@ -833,14 +1516,15 @@ class LibgammaScreen(Screen):
self.crtcs = []
if crtcs is not None:
crtcs = list(crtcs)
- for i in range(self.display.crtcs_available):
- crtc = LibgammaCRTC(self.screen, i)
+ for i in range(self.screen.crtcs_available):
+ crtc = LibgammaCRTC(self, i)
if (crtcs is None) or (i in crtcs) or (crtc.connector_name in crtcs):
self.crtcs.append(crtc)
elif isinstance(crtc.edid, str) and (crtc.edid.upper() in crtcs):
self.crtcs.append(crtc)
else:
del crtc
+
@property
def backend(self):
@@ -852,20 +1536,18 @@ class LibgammaScreen(Screen):
'''
return 'libgamma'
+
def __restore_all_crtcs(self):
'''
Restore the CLUT:s to the (configured) system defaults, for each CRTC
'''
- for crtc for self.crtcs:
+ for crtc in self.crtcs:
crtc.restore()
+
class LibgammaDisplay(Display):
'''
A display using the libgamma backend
-
- @variable screens:list<LibgammaScreen> The screens in the display
- @variable crtcs:list<LibgammaCRTC> The CRTC:s in the display
- @variable cooperative:bool Whether the adjustment method supports cooperative gamma
'''
def __init__(self, method = None, display = None, screens = None, crtcs = None):
'''
@@ -903,10 +1585,11 @@ class LibgammaDisplay(Display):
cs = crtcs
if isinstance(cs, dict):
cs = cs[screen] if screen in cs else []
- screen = LibgammaScreen(self.site, screen, cs)
+ screen = LibgammaScreen(self, screen, cs)
self.screens.append(screen)
self.crtcs.extend(screen.crtcs)
+
@property
def backend(self):
'''
@@ -917,6 +1600,7 @@ class LibgammaDisplay(Display):
'''
return 'libgamma'
+
@property
def lowest_priority(self):
'''
@@ -930,6 +1614,7 @@ class LibgammaDisplay(Display):
'''
return None
+
@property
def highest_priority(self):
'''
@@ -943,13 +1628,15 @@ class LibgammaDisplay(Display):
'''
return None
+
def __restore_all_partitions(self):
'''
Restore the CLUT:s to the (configured) system defaults, for each screen
'''
- for screen for self.screens:
+ for screen in self.screens:
screen.restore()
+
def get_adjustment_methods(libgamma_level = 0):
'''
Returns a list of available adjustment methods
@@ -969,18 +1656,19 @@ def get_adjustment_methods(libgamma_level = 0):
import libgamma
lgamma_meths = libgamma.list_methods(libgamma_level)
lgamma_map = {
- libgamma.LIBGAMMA_METHOD_DUMMY = 'dummy',
- libgamma.LIBGAMMA_METHOD_X_RANDR = 'randr',
- libgamma.LIBGAMMA_METHOD_X_VIDMODE = 'vidmode'
- libgamma.LIBGAMMA_METHOD_LINUX_DRM = 'drm',
- libgamma.LIBGAMMA_METHOD_W32_GDI = 'w32gdi',
- libgamma.LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS = 'quartz'
+ libgamma.LIBGAMMA_METHOD_DUMMY : 'dummy',
+ libgamma.LIBGAMMA_METHOD_X_RANDR : 'randr',
+ libgamma.LIBGAMMA_METHOD_X_VIDMODE : 'vidmode',
+ libgamma.LIBGAMMA_METHOD_LINUX_DRM : 'drm',
+ libgamma.LIBGAMMA_METHOD_W32_GDI : 'w32gdi',
+ libgamma.LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS : 'quartz'
}
ret += [lgamma_map[m] if m in lgamma_map else m for m in lgamma_meths]
except:
pass
return ret
+
def get_outputs(method = None, display = None, screens = None, crtcs = None):
'''
Get access to CRTC for editing the their gamma ramps
@@ -1003,14 +1691,19 @@ def get_outputs(method = None, display = None, screens = None, crtcs = None):
@return :Display A display
'''
if isinstance(method, str):
- lgamma_meths = {
- 'dummy' = libgamma.LIBGAMMA_METHOD_DUMMY,
- 'randr' = libgamma.LIBGAMMA_METHOD_X_RANDR,
- 'vidmode' = libgamma.LIBGAMMA_METHOD_X_VIDMODE,
- 'drm' = libgamma.LIBGAMMA_METHOD_LINUX_DRM,
- 'w32gdi' = libgamma.LIBGAMMA_METHOD_W32_GDI,
- 'quartz' = libgamma.LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS
- }
- return LibgammaDisplay(lgamma_meths[method], display, screen, crtc)
+ #try:
+ import libgamma
+ lgamma_meths = {
+ 'dummy' : libgamma.LIBGAMMA_METHOD_DUMMY,
+ 'randr' : libgamma.LIBGAMMA_METHOD_X_RANDR,
+ 'vidmode' : libgamma.LIBGAMMA_METHOD_X_VIDMODE,
+ 'drm' : libgamma.LIBGAMMA_METHOD_LINUX_DRM,
+ 'w32gdi' : libgamma.LIBGAMMA_METHOD_W32_GDI,
+ 'quartz' : libgamma.LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS
+ }
+ return LibgammaDisplay(lgamma_meths[method], display, screens, crtcs)
+ #except:
+ # pass
+ #raise Exception("Adjustment method %s is not available" % method)
else:
return LibgammaDisplay(method, display, screen, crtc)