PyCairo 中的剪裁和屏蔽
在 PyCairo 教程的這個(gè)部分,我們將討論剪裁和屏蔽操作。
剪裁
裁剪 是將繪制限定在某一區(qū)域內(nèi)。這樣做有一些效率的因素,或者為了創(chuàng)建有趣的效果。PyCairo 有一個(gè) clip() 方法用于設(shè)置裁剪區(qū)域。
#!/usr/bin/python''' ZetCode PyCairo tutorialThis program shows how to perform clipping in PyCairo.author: Jan Bodnar website: zetcode.com last edited: August 2012 '''import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib import cairo import math import randomclass Example(Gtk.Window):def __init__(self):super(Example, self).__init__()self.init_ui()self.load_image()self.init_vars()def init_ui(self):self.darea = Gtk.DrawingArea()self.darea.connect("draw", self.on_draw)self.add(self.darea)GLib.timeout_add(100, self.on_timer)self.set_title("Clipping")self.resize(300, 200)self.set_position(Gtk.WindowPosition.CENTER)self.connect("delete-event", Gtk.main_quit)self.show_all()def load_image(self):self.image = cairo.ImageSurface.create_from_png("beckov.png")def init_vars(self):self.pos_x = 128self.pos_y = 128self.radius = 40self.delta = [3, 3]def on_timer(self):self.pos_x += self.delta[0]self.pos_y += self.delta[1]self.darea.queue_draw()return Truedef on_draw(self, wid, cr):w, h = self.get_size()if (self.pos_x < 0 + self.radius):self.delta[0] = random.randint(5, 9)elif (self.pos_x > w - self.radius):self.delta[0] = -random.randint(5, 9)if (self.pos_y < 0 + self.radius):self.delta[1] = random.randint(5, 9)elif (self.pos_y > h - self.radius):self.delta[1] = -random.randint(5, 9)cr.set_source_surface(self.image, 1, 1)cr.arc(self.pos_x, self.pos_y, self.radius, 0, 2 * math.pi)cr.clip()cr.paint()def main():app = Example()Gtk.main()if __name__ == "__main__":main()在這個(gè)例子中,我們將裁剪一幅圖片。一個(gè)圓圈在窗口區(qū)域移動,并顯示下面的圖片的一部分。這就好像我們通過一個(gè)洞看過去一樣。
def load_image(self):self.image = cairo.ImageSurface.create_from_png("beckov.png")這是下面的圖片。每一個(gè)定時(shí)器周期,我們將看到這幅圖片的一部分。
if (self.pos_x < 0 + self.radius):self.delta[0] = random.randint(5, 9)elif (self.pos_x > w - self.radius):self.delta[0] = -random.randint(5, 9)如果圓圈擊中了窗口的左邊或右邊,則圓圈移動的方向會隨機(jī)地改變。對于上邊和下邊也一樣。
cr.arc(self.pos_x, self.pos_y, self.radius, 0, 2 * math.pi)這一行給 Cairo 上下文添加一個(gè)圓形的 Path。
cr.clip()clip() 設(shè)置裁剪區(qū)域。裁剪區(qū)域是當(dāng)前正在使用的 Path。當(dāng)前的 path 由 arc() 方法調(diào)用創(chuàng)建。
cr.paint()paint() 用當(dāng)前的 source 描繪當(dāng)前裁剪區(qū)域內(nèi)的部分。
屏蔽
在 source 被應(yīng)用于 surface 之前,它首先會被過濾。mask 被用作一個(gè)過濾器。mask 決定 source 的哪個(gè)部分被應(yīng)用,而哪個(gè)部分不會。mask 不透明的部分允許復(fù)制 source。透明的部分則不允許復(fù)制 source 到 surface。
#!/usr/bin/python''' ZetCode PyCairo tutorialThis program demonstrates masking.author: Jan Bodnar website: zetcode.com last edited: August 2012 '''import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import cairoclass Example(Gtk.Window):def __init__(self):super(Example, self).__init__()self.init_ui()self.load_image()def init_ui(self):darea = Gtk.DrawingArea()darea.connect("draw", self.on_draw)self.add(darea)self.set_title("Masking")self.resize(310, 100)self.set_position(Gtk.WindowPosition.CENTER)self.connect("delete-event", Gtk.main_quit)self.show_all()def load_image(self):self.ims = cairo.ImageSurface.create_from_png("omen.png")def on_draw(self, wid, cr):cr.mask_surface(self.ims, 0, 0);cr.fill()def main():app = Example()Gtk.main()if __name__ == "__main__":main()在這個(gè)例子中,屏蔽決定了哪些地方需要繪制哪些地方不繪制。
cr.mask_surface(self.ims, 0, 0);cr.fill()我們使用一幅圖片作為 mask,這將會把它顯示在窗口中。
Blind down 效果
在這個(gè)代碼例子中,我們將 blind down 我們的圖片。這類似于我們使用的遮光窗簾。
#!/usr/bin/python''' ZetCode PyCairo tutorialThis program creates a blind down effect using masking operation.author: Jan Bodnar website: zetcode.com last edited: August 2012 '''import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib import cairo import mathclass Example(Gtk.Window):def __init__(self):super(Example, self).__init__()self.init_ui()self.load_image()self.init_vars()def init_ui(self):self.darea = Gtk.DrawingArea()self.darea.connect("draw", self.on_draw)self.add(self.darea)GLib.timeout_add(35, self.on_timer)self.set_title("Blind down")self.resize(325, 250)self.set_position(Gtk.WindowPosition.CENTER)self.connect("delete-event", Gtk.main_quit)self.show_all()def load_image(self):self.image = cairo.ImageSurface.create_from_png("beckov.png")def init_vars(self):self.timer = Trueself.h = 0self.iw = self.image.get_width()self.ih = self.image.get_height()self.ims = cairo.ImageSurface(cairo.FORMAT_ARGB32,self.iw, self.ih)def on_timer(self):if (not self.timer):return Falseself.darea.queue_draw()return Truedef on_draw(self, wid, cr):ic = cairo.Context(self.ims)ic.rectangle(0, 0, self.iw, self.h)ic.fill()self.h += 1if (self.h == self.ih):self.timer = Falsecr.set_source_surface(self.image, 10, 10)cr.mask_surface(self.ims, 10, 10)def main():app = Example()Gtk.main()if __name__ == "__main__":main()blend down 效果背后的想法相當(dāng)?shù)暮唵巍D像有 h 個(gè)像素高。我們繪制 0,1, 2… 個(gè) 1 像素高的行。每個(gè)周期,圖像的部分多出一像素的高度,直到整幅圖片都變得可見為止。
def load_image(self):self.image = cairo.ImageSurface.create_from_png("beckov.png")在 load_image() 方法中,我們由一幅 PNG 圖片創(chuàng)建一個(gè)圖片 surface。
def init_vars(self):self.timer = Trueself.h = 0self.iw = self.image.get_width()self.ih = self.image.get_height()self.ims = cairo.ImageSurface(cairo.FORMAT_ARGB32,self.iw, self.ih)在 init_vars() 方法中,我們初始化一些變量。我們初始化 self.timer 和 self.h 變量。我們獲取所加載的圖片的寬度和高度。然后我們創(chuàng)建一個(gè)空的圖像 surface。它將會被來自于先前我們所創(chuàng)建的圖像 surface 的像素行所填充。
ic = cairo.Context(self.ims)我們由空的圖像 source 創(chuàng)建一個(gè) cairo 上下文。
ic.rectangle(0, 0, self.iw, self.h)ic.fill()我們向最初為空的圖像中繪制一個(gè)矩形。矩形每個(gè)周期高出 1px。用這種方式創(chuàng)建的圖像將在后面作為一個(gè) mask。
self.h += 1將要顯示的圖像的高度被加了一個(gè)單元。
if (self.h == self.ih):self.timer = False當(dāng)我們在 GTK 窗口中繪制了整個(gè)圖片時(shí),我們停掉定時(shí)器方法。
cr.set_source_surface(self.image, 10, 10)cr.mask_surface(self.ims, 10, 10)城堡的圖片被設(shè)置為繪制時(shí)的 source。mask_surface() 繪制當(dāng)前的 source,使用 surface 的 alpha 通道作為一個(gè) mask。
Blind down 是一種動畫效果。
本章討論了PyCairo中的裁剪和屏蔽。
原文
Done.
總結(jié)
以上是生活随笔為你收集整理的PyCairo 中的剪裁和屏蔽的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Brotli压缩算法的Android封装
- 下一篇: PyCairo 中的透明度