127 lines
3.2 KiB
Python
127 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import gi, cairo, math
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk, Gdk, GdkPixbuf
|
|
|
|
|
|
class ScaleImage(Gtk.Image):
|
|
def __init__(self, filepath):
|
|
Gtk.Image.__init__(self)
|
|
self.width = None
|
|
self.height = None
|
|
self.reset(filepath)
|
|
|
|
|
|
def reset(self, filepath, crop = False):
|
|
if type(filepath) == str:
|
|
self.origin = GdkPixbuf.Pixbuf.new_from_file(filepath)
|
|
else:
|
|
self.origin = filepath
|
|
|
|
if self.width is None:
|
|
self.pixbuf = self.origin
|
|
|
|
self.width = self.origin.get_width()
|
|
self.height = self.origin.get_height()
|
|
self.set_from_pixbuf(self.pixbuf)
|
|
else:
|
|
w = self.origin.get_width()
|
|
h = self.origin.get_height()
|
|
if crop and w != h:
|
|
size = min(self.width, self.height)
|
|
self.clip_resize(size)
|
|
else:
|
|
self.pixbuf = self.origin.scale_simple(self.width, self.height, GdkPixbuf.InterpType.BILINEAR)
|
|
|
|
return self
|
|
|
|
|
|
def resize(self, width, height):
|
|
self.width = width
|
|
self.height = height
|
|
self.pixbuf = self.origin.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
|
|
self.set_from_pixbuf(self.pixbuf)
|
|
return self
|
|
|
|
def clip_resize(self, size):
|
|
w = self.origin.get_width()
|
|
h = self.origin.get_height()
|
|
_size = min(w, h) # 按小边裁剪成正方形
|
|
size = min(size, _size) # 缩放按最小值来
|
|
self.width = size
|
|
self.height = size
|
|
|
|
surface = cairo.ImageSurface(cairo.Format.ARGB32, w, h)
|
|
ctx = cairo.Context(surface)
|
|
Gdk.cairo_set_source_pixbuf(ctx, self.origin, 0, 0)
|
|
|
|
ctx.line_to(0, 0)
|
|
ctx.line_to(_size, 0)
|
|
ctx.line_to(_size, _size)
|
|
ctx.line_to(0, _size)
|
|
|
|
ctx.close_path()
|
|
|
|
ctx.clip()
|
|
ctx.paint()
|
|
|
|
pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, _size, _size)
|
|
|
|
self.pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.BILINEAR)
|
|
self.set_from_pixbuf(self.pixbuf)
|
|
|
|
return self
|
|
|
|
def set_radius(self, radius = 0):
|
|
w = self.width
|
|
h = self.height
|
|
surface = cairo.ImageSurface(cairo.Format.ARGB32, w, h)
|
|
ctx = cairo.Context(surface)
|
|
Gdk.cairo_set_source_pixbuf(ctx, self.pixbuf, 0, 0)
|
|
|
|
# 左上角 圆角
|
|
ctx.arc(radius, radius, radius, -math.pi, -math.pi / 2)
|
|
ctx.line_to(w - radius, 0)
|
|
|
|
# 右上角 圆角
|
|
ctx.arc(w - radius, radius, radius, -math.pi / 2, 0)
|
|
ctx.line_to(w, -radius)
|
|
|
|
# 右下角 圆角
|
|
ctx.arc(w - radius, h - radius, radius, 0, math.pi / 2)
|
|
ctx.line_to(radius, h)
|
|
|
|
# 左下角 圆角
|
|
ctx.arc(radius, h - radius, radius, math.pi / 2, math.pi)
|
|
ctx.close_path()
|
|
|
|
ctx.clip()
|
|
ctx.paint()
|
|
|
|
pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h)
|
|
self.set_from_pixbuf(pixbuf)
|
|
return self
|
|
|
|
|
|
# 旋转不生效
|
|
def rotate(self, deg = 0, point = None):
|
|
w = self.width
|
|
h = self.height
|
|
surface = cairo.ImageSurface(cairo.Format.ARGB32, w, h)
|
|
ctx = cairo.Context(surface)
|
|
Gdk.cairo_set_source_pixbuf(ctx, self.pixbuf, 0, 0)
|
|
|
|
# 圆心坐标
|
|
if point is None:
|
|
point = (w / 2, h / 2)
|
|
|
|
ctx.translate(point[0], point[1])
|
|
ctx.rotate((deg / 180) * math.pi)
|
|
|
|
ctx.paint()
|
|
|
|
pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h)
|
|
|
|
self.set_from_pixbuf(pixbuf)
|
|
return self |