#!/usr/bin/env python3 import gi, cairo, math gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkPixbuf from utils import empty_pixbuf class ScaleImage(Gtk.Image): def __init__(self, filepath = empty_pixbuf): 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 or empty_pixbuf 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) self.set_from_pixbuf(self.pixbuf) 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