1# -*- coding: utf-8 -*-2# Copyright 2011 Takeshi KOMIYA3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.1516from __future__ import division1718import math19import re202122class XY(tuple):23 mapper = dict(x=0, y=1)2425 def __new__(cls, x, y):26 return super(XY, cls).__new__(cls, (x, y))2728 def __getattr__(self, name):29 try:30 return self[self.mapper[name]]31 except KeyError:32 raise AttributeError(name)3334 def __setattr__(self, name, value):35 raise TypeError("'XY' object does not support item assignment")3637 def shift(self, x=0, y=0):38 return self.__class__(self.x + x, self.y + y)394041class Size(tuple):42 def __new__(cls, width, height):43 return super(Size, cls).__new__(cls, (width, height))444546 def width(self):47 return self[0]484950 def height(self):51 return self[1]5253 def resize(self, **kwargs):54 if 'width' in kwargs and 'height' in kwargs:55 size = Size(float(kwargs['width']), float(kwargs['height']))56 elif 'width' in kwargs:57 width = float(kwargs['width'])58 size = Size(width, self.height * width / self.width)59 elif 'height' in kwargs:60 height = float(kwargs['height'])61 size = Size(self.width * height / self.height, height)62 else:63 size = self6465 if 'scale' in kwargs:66 scale = float(kwargs['scale']) / 10067 size = Size(size.width * scale, size.height * scale)6869 return size7071 def to_integer_point(self):72 return Size(int(self.width), int(self.height))737475class Box(list):76 mapper = dict(x1=0, y1=1, x2=2, y2=3, x=0, y=1)7778 def __init__(self, x1, y1, x2, y2):79 super(Box, self).__init__((x1, y1, x2, y2))8081 def __getattr__(self, name):82 try:83 return self[self.mapper[name]]84 except KeyError:85 raise AttributeError(name)8687 def __repr__(self):88 _format = "<%s (%s, %s) %dx%d at 0x%08x>"89 params = (self.__class__.__name__, self.x1, self.y1,90 self.width, self.height, id(self))91 return _format % params9293 def shift(self, x=0, y=0):94 return self.__class__(self.x1 + x, self.y1 + y,95 self.x2 + x, self.y2 + y)9697 def get_padding_for(self, size, **kwargs):98 valign = kwargs.get('valign', 'center')99 halign = kwargs.get('halign', 'center')100 padding = kwargs.get('padding', 0)101102 if halign == 'left':103 dx = padding104 elif halign == 'right':105 dx = self.size.width - size.width - padding106 else:107 dx = int(math.ceil((self.size.width - size.width) / 2.0))108109 if valign == 'top':110 dy = padding111 elif valign == 'bottom':112 dy = self.size.height - size.height - padding113 else:114 dy = int(math.ceil((self.size.height - size.height) / 2.0))115116 return dx, dy117118119 def size(self):120 return Size(self.width, self.height)121122123 def width(self):124 return self.x2 - self.x1125126127 def height(self):128 return self.y2 - self.y1129130131 def topleft(self):132 return XY(self.x1, self.y1)133134135 def top(self):136 return XY(self.x1 + self.width // 2, self.y1)137138139 def topright(self):140 return XY(self.x2, self.y1)141142143 def bottomleft(self):144 return XY(self.x1, self.y2)145146147 def bottom(self):148 return XY(self.x1 + self.width // 2, self.y2)149150151 def bottomright(self):152 return XY(self.x2, self.y2)153154155 def left(self):156 return XY(self.x1, self.y1 + self.height // 2)157158159 def right(self):160 return XY(self.x2, self.y1 + self.height // 2)161162163 def center(self):164 return XY(self.x1 + self.width // 2, self.y1 + self.height // 2)165166 def to_integer_point(self):167 return Box(*[int(i) for i in self])168169170def unquote(string):171 """ Remove quotas from string """172 if string:173 string = string.replace('"""', '').replace("'''", '')174175 m = re.match(r'\A(?P<quote>"|\')((.|\s)*)(?P=quote)\Z', string, re.M)176 if m:177 return re.sub("\\\\" + m.group(1), m.group(1), m.group(2))178 else:179 return string180 else:181 return string182183184def is_Pillow_available():185 try:186 from PIL import _imagingft187 _imagingft188 return True189 except ImportError:190 return False