%PDF- %PDF-
Direktori : /usr/lib/calibre/calibre/ebooks/pdf/render/ |
Current File : //usr/lib/calibre/calibre/ebooks/pdf/render/gradients.py |
#!/usr/bin/env python3 __license__ = 'GPL v3' __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>' __docformat__ = 'restructuredtext en' import sys, copy from collections import namedtuple from qt.core import QLinearGradient, QPointF, sip from calibre.ebooks.pdf.render.common import Name, Array, Dictionary Stop = namedtuple('Stop', 't color') class LinearGradientPattern(Dictionary): def __init__(self, brush, matrix, pdf, pixel_page_width, pixel_page_height): self.matrix = (matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), matrix.dx(), matrix.dy()) gradient = sip.cast(brush.gradient(), QLinearGradient) start, stop, stops = self.spread_gradient(gradient, pixel_page_width, pixel_page_height, matrix) # TODO: Handle colors with different opacities self.const_opacity = stops[0].color[-1] funcs = Array() bounds = Array() encode = Array() for i, current_stop in enumerate(stops): if i < len(stops) - 1: next_stop = stops[i+1] func = Dictionary({ 'FunctionType': 2, 'Domain': Array([0, 1]), 'C0': Array(current_stop.color[:3]), 'C1': Array(next_stop.color[:3]), 'N': 1, }) funcs.append(func) encode.extend((0, 1)) if i+1 < len(stops) - 1: bounds.append(next_stop.t) func = Dictionary({ 'FunctionType': 3, 'Domain': Array([stops[0].t, stops[-1].t]), 'Functions': funcs, 'Bounds': bounds, 'Encode': encode, }) shader = Dictionary({ 'ShadingType': 2, 'ColorSpace': Name('DeviceRGB'), 'AntiAlias': True, 'Coords': Array([start.x(), start.y(), stop.x(), stop.y()]), 'Function': func, 'Extend': Array([True, True]), }) Dictionary.__init__(self, { 'Type': Name('Pattern'), 'PatternType': 2, 'Shading': shader, 'Matrix': Array(self.matrix), }) self.cache_key = (self.__class__.__name__, self.matrix, tuple(shader['Coords']), stops) def spread_gradient(self, gradient, pixel_page_width, pixel_page_height, matrix): start = gradient.start() stop = gradient.finalStop() stops = list(map(lambda x: [x[0], x[1].getRgbF()], gradient.stops())) spread = gradient.spread() if spread != gradient.PadSpread: inv = matrix.inverted()[0] page_rect = tuple(map(inv.map, ( QPointF(0, 0), QPointF(pixel_page_width, 0), QPointF(0, pixel_page_height), QPointF(pixel_page_width, pixel_page_height)))) maxx = maxy = -sys.maxsize-1 minx = miny = sys.maxsize for p in page_rect: minx, maxx = min(minx, p.x()), max(maxx, p.x()) miny, maxy = min(miny, p.y()), max(maxy, p.y()) def in_page(point): return (minx <= point.x() <= maxx and miny <= point.y() <= maxy) offset = stop - start llimit, rlimit = start, stop reflect = False base_stops = copy.deepcopy(stops) reversed_stops = list(reversed(stops)) do_reflect = spread == gradient.ReflectSpread totl = abs(stops[-1][0] - stops[0][0]) intervals = [abs(stops[i+1][0] - stops[i][0])/totl for i in range(len(stops)-1)] while in_page(llimit): reflect ^= True llimit -= offset estops = reversed_stops if (reflect and do_reflect) else base_stops stops = copy.deepcopy(estops) + stops first_is_reflected = reflect reflect = False while in_page(rlimit): reflect ^= True rlimit += offset estops = reversed_stops if (reflect and do_reflect) else base_stops stops = stops + copy.deepcopy(estops) start, stop = llimit, rlimit num = len(stops) // len(base_stops) if num > 1: # Adjust the stop parameter values t = base_stops[0][0] rlen = totl/num reflect = first_is_reflected ^ True intervals = [i*rlen for i in intervals] rintervals = list(reversed(intervals)) for i in range(num): reflect ^= True pos = i * len(base_stops) tvals = [t] for ival in (rintervals if reflect and do_reflect else intervals): tvals.append(tvals[-1] + ival) for j in range(len(base_stops)): stops[pos+j][0] = tvals[j] t = tvals[-1] # In case there were rounding errors stops[-1][0] = base_stops[-1][0] return start, stop, tuple(Stop(s[0], s[1]) for s in stops)