2019/11/02(土) [n年前の日記]
#1 [kivy][python] Kivyのcanvasに描画した図形をファイル保存
Kivy の canvas に描画した図形を画像ファイルとして保存できるかどうか調べたり。
Kivy の Widget には、export_to_png() というメソッドがあって、ソレを使えば pngファイルとしてWidget内の様子を画像保存できる模様。
動作確認環境は、Windows10 x64 1903 + Python 2.7.17 32bit + Kivy 1.11.1。
Kivy の Widget には、export_to_png() というメソッドがあって、ソレを使えば pngファイルとしてWidget内の様子を画像保存できる模様。
動作確認環境は、Windows10 x64 1903 + Python 2.7.17 32bit + Kivy 1.11.1。
◎ 動作確認。 :
以下のように表示されるスクリプトを書いて動作確認。
ソースは以下。
_02_canvas2.py
Save をクリックして保存されたpngファイルは以下。
ちゃんと保存されてるっぽい。
- Drawをクリックすると図形を描画。
- Save をクリックすると、output.png という画像ファイル名で見た目を保存。
ソースは以下。
_02_canvas2.py
from kivy.app import App from kivy.uix.widget import Widget from kivy.uix.image import Image from kivy.graphics import Ellipse from kivy.graphics import Line from kivy.graphics import Rectangle from kivy.graphics import Color from kivy.graphics import Translate from kivy.graphics.texture import Texture from kivy.properties import ObjectProperty from kivy.lang import Builder from kivy.config import Config Config.set('graphics', 'width', '512') Config.set('graphics', 'height', '512') output_filename = "./output.png" # my.kv Builder.load_string(''' #:kivy 1.11.1 <MyWidget>: BoxLayout: size: root.size orientation: "vertical" MyPaintImage: id: myimage texture: self.texture_image size_hint_y: 0.9 canvas.before: Color: rgba: 0, 0, 0, 1 Rectangle: pos: self.pos size: self.size BoxLayout: size_hint_y: 0.1 Button: id: btn_draw text: "Draw" on_press: myimage.draw_shapes() Button: id: btn_save text: "Save" on_press: myimage.save_canvas_image() ''') class MyPaintImage(Image): texture_image = ObjectProperty(None) def __init__(self, **kwargs): super(MyPaintImage, self).__init__(**kwargs) self.texture_image = Texture.create(size=self.size) def draw_shapes(self): bx, by = self.pos with self.canvas: Translate(bx, by) Color(0.1, 0.4, 0.1) Rectangle(pos=(0, 0), size=self.size) Color(0, 0.75, 0) Rectangle(pos=(16, 64), size=(300, 200)) poslist = [ 32, 32, 480, 420, 480, 32, ] Color(1, 0, 0, .3) Line(points=poslist, width=6, close='True') Color(0, .5, 1, 0.5) Ellipse(pos=(76, 50), size=(360, 360)) Translate(-bx, -by) def save_canvas_image(self): self.export_to_png(filename=output_filename, scale=1.0) print("save %s" % output_filename) class MyWidget(Widget): def __init__(self, **kwargs): super(MyWidget, self).__init__(**kwargs) class MyApp(App): def __init__(self, **kwargs): super(MyApp, self).__init__(**kwargs) self.title = 'Simple Graphics Test 2' def build(self): return MyWidget() if __name__ == '__main__': MyApp().run()
- 今回は、.kv ファイルを .py の中に含めて記述してみた。Builder.load_string(''' ... ''') の中に、.kv の内容が記述されている。
- .kv の中で、自作クラスを記述することもできるらしい。今回、MyPaintImage を作っているけれど、そのクラス名も記述できている。
- draw_shapes() が、canvas に図形を描画している部分。
- save_canvas_image() が、その Widget の見た目を画像保存してる部分。
- draw_shapes() の中で Translate(x, y) が呼ばれているけど、これをしておかないと、その Widget の位置ではなく、ウインドウ全体の位置で描画されてしまう。図形を描画し終わったら、元の位置に戻すための Translate(x, y) を呼ぶ。
Save をクリックして保存されたpngファイルは以下。
ちゃんと保存されてるっぽい。
◎ 課題。 :
canvasサイズを指定することはできるのだろうか…。例えば、512x512、1024x1024、2048x2048等に決め打ちできれば、画像生成をするためのツールなども作れそうだけど…。
ウインドウサイズを変更すると canvasサイズも変わってしまってゴミが見えてしまうのだけど。texture に図形を描画することができれば、Image に texture を指定することでそういう問題は起きないはず。ただ、texture に図形描画をする方法が分からない。Kivy でそんなことはできるのだろうか…。
ウインドウサイズを変更すると canvasサイズも変わってしまってゴミが見えてしまうのだけど。texture に図形を描画することができれば、Image に texture を指定することでそういう問題は起きないはず。ただ、texture に図形描画をする方法が分からない。Kivy でそんなことはできるのだろうか…。
[ ツッコむ ]
#2 [aggdraw][python] aggdrawを試用してみた
Pillow の Image に、アンチエイリアスをかけた状態で図形描画等ができる、aggdraw なるライブラリがあるらしいので少し試用してみたり。
_aggdraw - PyPI
_pytroll/aggdraw: Python package wrapping AGG2 drawing functionality
_AggDraw - aggdraw 1.3.8 documentation
環境は、Windows10 x64 1903 + Python 2.7.17 + Pillow 6.2.1 + aggdraw 1.3.11。
インストールは、以下でいいのかな。たぶん。
_aggdraw - PyPI
_pytroll/aggdraw: Python package wrapping AGG2 drawing functionality
_AggDraw - aggdraw 1.3.8 documentation
環境は、Windows10 x64 1903 + Python 2.7.17 + Pillow 6.2.1 + aggdraw 1.3.11。
インストールは、以下でいいのかな。たぶん。
pip install aggdraw
◎ aggdrawで描いてみた事例。 :
_01_aggdraw.py
出力結果。
_output_aggdraw.png
アンチエイリアスがかかっている。
from PIL import Image import aggdraw import math # aggdraw im = Image.new('RGBA', (512, 512), (255, 255, 255, 255)) d = aggdraw.Draw(im) pen = aggdraw.Pen((0, 0, 0, 255), 2.0) # color, width cx, cy = 256, 256 for i in range(0, 360, 5): x = 240 * math.cos(math.radians(i)) + cx y = 240 * math.sin(math.radians(i)) + cy d.line((cx, cy, x, y), pen) d.flush() im.save("./output_aggdraw.png")
出力結果。
アンチエイリアスがかかっている。
◎ ImageDrawで描いてみた事例。 :
Pillow の ImageDraw を使って描いてみた事例。
_02_imagedraw.py
_output_imagedraw.png
アンチエイリアスがかかってないのが分かる。
_02_imagedraw.py
from PIL import Image, ImageDraw import math # ImageDraw im = Image.new("RGBA", (512, 512), (255, 255, 255, 255)) d = ImageDraw.Draw(im) cx, cy = 256, 256 for i in range(0, 360, 5): x = int(240 * math.cos(math.radians(i)) + cx) y = int(240 * math.sin(math.radians(i)) + cy) d.line((cx, cy, x, y), fill=(0, 0, 0, 255), width=2) im.save("./output_imagedraw.png")
アンチエイリアスがかかってないのが分かる。
◎ ImageDrawで描いてみた事例その2。 :
Pillow の ImageDraw を使って描いてみた事例。2倍のサイズで描いてから、1/2に縮小してみる。
_03_imagedraw2.py
_output_imagedraw2.png
若干それっぽくアンチエイリアスがかかったような雰囲気にはなっている。
_03_imagedraw2.py
from PIL import Image, ImageDraw import math # ImageDraw im = Image.new("RGBA", (1024, 1024), (255, 255, 255, 255)) d = ImageDraw.Draw(im) cx, cy = (256 * 2), (256 * 2) for i in range(0, 360, 5): x = int((240 * 2) * math.cos(math.radians(i)) + cx) y = int((240 * 2) * math.sin(math.radians(i)) + cy) d.line((cx, cy, x, y), fill=(0, 0, 0, 255), width=(2 * 2)) im.thumbnail((512, 512), Image.ANTIALIAS) im.save("./output_imagedraw2.png")
若干それっぽくアンチエイリアスがかかったような雰囲気にはなっている。
◎ 問題点。 :
aggdraw のライセンスがちょっとよくわからない。一般的なライセンスではないようで。
aggdraw が使っている AGG とやらにバグがあったりもするようで、例えば透明度を指定すると色が妙なことになる時もあるっぽい。
_Brush/Pen transparency weirdness - Issue #16 - pytroll/aggdraw
aggdraw が使っている AGG とやらにバグがあったりもするようで、例えば透明度を指定すると色が妙なことになる時もあるっぽい。
_Brush/Pen transparency weirdness - Issue #16 - pytroll/aggdraw
[ ツッコむ ]
以上、1 日分です。