%PDF- %PDF-
Direktori : /usr/lib/python3/dist-packages/rlPyCairo/ |
Current File : //usr/lib/python3/dist-packages/rlPyCairo/gstate.py |
__all__ = ( 'GState', ) import sys try: import cairocffi as cairo #prefer cairocffi except ImportError: import cairo from reportlab.lib.colors import toColor from reportlab.graphics.transform import mmult from PIL import Image as PILImage class GState(object): __fill_rule_values = (1,0) def __init__(self, width=1, height=1, bg='white', fmt='RGB24'): self._fmt = fmt self.surface = cairo.ImageSurface(self.__str2format(fmt), width, height) self.width = width self.height = height self.ctx = ctx = cairo.Context(self.surface) if fmt=='RGB24': self.__set_source_color__ = lambda c:ctx.set_source_rgb(*c.rgb()) elif fmt=='ARGB32': self.__set_source_color__ = lambda c:ctx.set_source_rgba(*c.rgba()) else: raise ValueError('Bad fmt=%r for rlPyCairo.GState' % fmt) ctx.set_antialias(cairo.ANTIALIAS_BEST) self._in_transform = self._out_transform = (1,0,0,-1,0,height) self.ctm = (1,0,0,1,0,0) self.fillColor = bg ctx.rectangle(0,0,width,height) self.pathFill() self.pathBegin() self.__fillColor = self.__strokeColor = None def _text2PathDescription(text, x, y): try: from reportlab.graphics.utils import text2PathDescription, FTTextPath gs = FTTextPath() except ImportError: try: from _rl_renderPM import gstate except ImportError: try: from reportlab.graphics._renderPM import gstate except ImportError as _e: raise ImportError('freetype-py is not installed and no libart based _renderPM can be imported') from _e from reportlab.graphics.utils import text2PathDescription gs = gstate(1,1) def _text2PathDescription(text, x, y): return text2PathDescription( text, x=x, y=y, fontName=self.fontName, fontSize=self.fontSize, truncate=False, gs=gs, ) self._text2PathDescription = _text2PathDescription return _text2PathDescription(text, x, y) self._text2PathDescription = _text2PathDescription self.__pathOpMap__ = dict( moveTo=ctx.move_to, lineTo=ctx.line_to, curveTo=ctx.curve_to, closePath=ctx.close_path, ) self.textRenderMode = 0 @staticmethod def __str2format(fmt): return getattr(cairo,'FORMAT_'+fmt) @property def pixBuf(self): ba = self.surface.get_data() #despite the name they store it in 32 bits; we need to remove 8 ba = bytearray(ba) if sys.byteorder=='little': #BGRA --> RGBA for i in range(0,len(ba),4): ba[i:i+3] = bytearray(reversed(ba[i:i+3])) else: #ARGB --> RGBA for i in range(0,len(ba),4): ba[i+3],ba[i:i+3] = ba[i],ba[i+1:i+4] if self._fmt=='RGB24': del ba[3::4] #we have red green blue spare return bytes(ba) @property def ctm(self): return mmult(self._out_transform,tuple(self.ctx.get_matrix())) @ctm.setter def ctm(self,mx): nctm = mmult(self._in_transform,mx) self.ctx.set_matrix(cairo.Matrix(*nctm)) @property def fillColor(self): return self.__fillColor @fillColor.setter def fillColor(self,c): self.__fillColor = toColor(c) if c is not None else c @property def strokeColor(self): return self.__strokeColor @strokeColor.setter def strokeColor(self,c): self.__strokeColor = toColor(c) if c is not None else c @property def strokeWidth(self): return self.ctx.get_line_width() @strokeWidth.setter def strokeWidth(self, w): return self.ctx.set_line_width(w) @property def dashArray(self): return self.ctx.get_dash() @dashArray.setter def dashArray(self, da): if not da or not isinstance(da,(list,tuple)): da = 0, () else: if isinstance(da[0],(list,tuple)): da = da[1],da[0] return self.ctx.set_dash(da[1], da[0]) #lucky Cairo uses the same linCap/Join number values as PDF @property def lineCap(self): return int(self.ctx.get_line_cap()) @lineCap.setter def lineCap(self, v): return self.ctx.set_line_cap(int(v)) @property def lineJoin(self): return int(self.ctx.get_line_join()) @lineJoin.setter def lineJoin(self, v): return self.ctx.set_line_join(int(v)) #the values are the other way round from PDF @property def fillMode(self): return self.__fill_rule_values[int(self.ctx.get_fill_rule())] @fillMode.setter def fillMode(self, v): return self.ctx.set_fill_rule(self.__fill_rule_values[int(v)]) def beginPath(self): self.ctx.new_path() def moveTo(self, x, y): self.ctx.move_to(float(x), float(y)) def lineTo(self, x, y): self.ctx.line_to(float(x), float(y)) def pathClose(self): self.ctx.close_path() def pathFill(self,fillMode=None): if self.__fillColor: if fillMode is not None: ofm = self.fillMode if ofm!=fillMode: self.fillMode = fillMode self.__set_source_color__(self.__fillColor) self.ctx.fill_preserve() if fillMode is not None and ofm!=fillMode: self.fillMode = ofm def pathStroke(self): if self.__strokeColor and self.strokeWidth>0: self.__set_source_color__(self.__strokeColor) self.ctx.stroke_preserve() def curveTo(self, x1, y1, x2, y2, x3, y3): self.ctx.curve_to(float(x1), float(y1),float(x2), float(y2),float(x3), float(y3)) def pathBegin(self): self.ctx.new_path() def clipPathClear(self): self.ctx.rest_clip() def clipPathSet(self): ctx = self.ctx oPath = ctx.copy_path() ctx.new_path() ctx.clip() ctx.new_path() ctx.append_path(oPath) def clipPathAdd(self): self.ctx.clip_preserve() def setFont(self, fontName, fontSize): self.fontName = fontName self.fontSize = fontSize def drawString(self, x, y, text): opMap = self.__pathOpMap__ oPath = self.ctx.copy_path() oFM = self.fillMode tRM = self.textRenderMode try: self.ctx.new_path() for op in self._text2PathDescription(text, x, y): #call one of ctx.move_to/line_to/curve_to/close_path opMap[op[0]](*op[1:]) if tRM in (0,2,4,6): self.pathFill(0) if tRM in (1,2,5,6): self.pathStroke() if tRM>=4: self.ctx.clip_preserve() finally: self.ctx.new_path() self.ctx.append_path(oPath) self.fillMode = oFM @classmethod def __fromPIL(cls, im, fmt='RGB24', alpha=1.0, forceAlpha=False): mode = im.mode im = im.copy() argb = fmt=='ARGB32' if mode=='RGB': im.putalpha(int(alpha * 255)) if alpha!=1 and argb: im = im.convert('RGBa') elif mode=='RGBA' or forceAlpha: if forceAlpha: im.putalpha(int(alpha * 255)) if argb: im = im.convert('RGBa') elif mode=='RGBa' or forceAlpha: if forceAlpha: im = im.convert('RGBA') im.putalpha(int(alpha * 255)) if argb: im = im.convert('RGBa') fmt = cls.__str2format(fmt) # TODO need to fix this up for bigendian when cairo order is not BGRa if sys.byteorder=='little': ba = im.tobytes('raw','BGRa') else: ba = bytearray(im.tobytes('raw','RGBa')) for i in range(0,len(ba),4): ba[i],ba[i+1:i+4] = ba[i+3],ba[i:i+3] ba = bytes(ba) return cairo.ImageSurface.create_for_data(bytearray(ba), fmt, im.width, im.height, cairo.ImageSurface.format_stride_for_width(fmt,im.width), ) def _aapixbuf(self, x, y, dstW, dstH, data, srcW, srcH, planes=3, ): ctx = self.ctx ctx.save() ctx.set_antialias(cairo.ANTIALIAS_DEFAULT) ctx.set_operator(cairo.OPERATOR_OVER) ctx.translate(x,y+dstH) ctx.scale(dstW/float(srcW),-dstH/float(srcH)) ctx.set_source_surface(self.__fromPIL(data,self._fmt, forceAlpha=False)) ctx.paint() ctx.restore()