[Kivy] imageに表示した画像を拡大・縮小する

imageに表示した画像を拡大・縮小する

 ウィンドウサイズよりも大きな画像を表示する場合、①画像の全体と②画像の指定した場所を拡大表示したものとを交互に表示できたら、全体像と表示したい部分の詳細の確認がスムーズにおこなえて大変便利です。

 今回のサンプルプログラムでは、ウィンドウサイズよりも大きい画像を使用して、ウィンドウ上のImageにその画像を縮小して全体表示します。その全体表示した画像の一部をマウスでダブルクリックすると、ダブルクリックをした部分を中心に画像を等倍表示(拡大)するようにします。再度、マウスで画像をダブルクリックすると画像は全体表示に戻るというように、全体表示と拡大表示とを繰り返すようにします。

 Imageのサイズ: 640×360)、  画像のサイズ:1920×1080

画像の拡大・縮小表示について

 今回のサンプルプログラムでは、画像の拡大、縮小するために、以下の設定をおこないました。
 1. 画像を表示するImageを、ScrollViewに載せる。
 2. Imageに画像を表示する。
3. Image上でのマウスのダブルクリックを認識する。
4. 画像の全体表示と等倍表示の切り替えをおこなう。

1. 画像を表示するImageを、ScrollViewに載せる。

 ウィンドウよりも大きな画像を等倍表示して任意の場所を表示できるようにするには、ImageをScrollViewに載せます。
 ScrollViewは、do_scroll_x、do_scroll_yによりスクロールを有効にして、サイズを640、360(ウィンドウサイズからBoxLayoutの余白分を減らしたサイズ)にします。サイズを指定しておかないと、ScrollViewのデフォルトサイズ(100、100)に画像が表示されてしまいます。

 Imageの設定は、fit_modeに’scale-down’を指定して、貼り付ける画像がImage内に収まるように縮小するようにします。そして、全体表示の場合はImageのtextureサイズをScrollViewと同じに、等倍表示の場合はImageのtextureサイズを貼り付ける画像と同じサイズにすることで、画像の全体表示と等倍表示を実現しています。

 Imageでは、その他にon_touch_downでマウスクリックされた場合に呼び出す関数を指定しており、Imageのtextureを変更したのを反映させるためにsize_hintにNoneを指定しています。

        ScrollView:
            id: scrollview
            size: 640, 360
            do_scroll_x: True
            do_scroll_y: True

            Image:
                id: image
                fit_mode: 'scale-down'
                on_touch_down: root.on_image_down(args[1])
                size_hint: None, None

2. Imageに画像を表示する

 Imageに画像を表示するには、CoreImage()により対象の画像ファイルを読み込み、そのtextureをImage(self.ids.image)のtextureに入れます。

 画像を全体表示するために、Imageの幅と高さはScrollViewと同じに指定してImageのイベントであるupdate_from_scroll()により表示を更新することで、Imageに画像を表示します。

    def __init__(self, **kwargs):
        super(ImageTestWidget, self).__init__(**kwargs)

        # 画像ファイルの読み込み
        self.img1 = CoreImage('sample.png')
        # 読み込んだ画像をimageに設定
        self.ids.image.texture = self.img1.texture
        self.ids.image.width = self.ids.scrollview.width
        self.ids.image.height = self.ids.scrollview.height
        self.ids.scrollview.update_from_scroll()

3. Image上でのマウスのダブルクリックを認識する。

 マウスクリックがダブルクリックであったかの判定は、touch.is_double_tapで行えます。ダブルクリックされた場合は、touch.is_double_tapはTrueを返します。

 ※ touchは、kivy.input.motioneventです。

    def on_image_down(self, touch):
        # ダブルクリックであるかの判定
        if touch.is_double_tap:
       # ダブルクリックであった場合の処理
       …

4. 画像の全体表示と等倍表示の切り替えをおこなう

 画像の全体表示と等倍表示との切り替えは、①kvファイルのsize_hint_y、size_hint_xの値を変更して、②self.ids.scrollview.update_from_scroll()を実行することで行います。
 サンプルプログラムでは、画像をダブルクリックするごとにon_image_down内で、self.stateの値に応じて、全体表示もしくは等倍表示をおこないます。そして、作業後にはself.stateを変更作業をおこなっており、ダブルクリックする度に全体表示と等倍表示とが繰り返されます。

等倍表示の処理

 等倍表示では、①Image(self.ids.image)の幅と高さを、画像と同じ値に変更して、②画像の表示位置の指定をおこないます。

 等倍表示の時に表示する画像の位置は、scrollviewのscroll_xやscroll_yの値で指定します。これらは表示位置を0〜1で指定するので、以下のように表示位置を算出します。

 scrollview.scroll_x = マウスのクリック位置x / imageの幅 ※ 両方とも全体表示時の値
 scrollview.scroll_y = マウスのクリック位置y / imageの高さ ※ 両方とも全体表示時の値

 マウスのクリック位置はイベントon_image_down(self, touch)の中のtouchに含まれており、幅方向はtouch.pos[0]、高さ方向はtouch.pos[1]により取得できます。得られる座標は、imageの左下が原点(0, 0)であり、これはtouchの出力する座標の原点と同じです。 

            if self.state == 0:
                # 等倍表示の処 ①の作業
                self.ids.image.width = self.ids.image.texture.width
                self.ids.image.height = self.ids.image.texture.height

                # 表示位置の変更 ②の作業
                self.ids.scrollview.update_from_scroll()
                self.ids.scrollview.scroll_x = (
                    touch.pos[0] / self.ids.scrollview.width)
                self.ids.scrollview.scroll_y = (
                    touch.pos[1] / self.ids.scrollview.height)
                self.state = 1

全体表示の処理

 全体表示では画像を読み込んで表示した時と同じように、Imageの幅と高さをScrollViewと同じにして、更新をおこないます。

            else:
                # 画面に合わせた表示の処理
                self.ids.image.width = self.ids.scrollview.width
                self.ids.image.height = self.ids.scrollview.height
                self.ids.scrollview.update_from_scroll()
                self.state = 0

サンプルプログラム

 サンプルプログラムを実行すると、左図のような画面が表示されます。image部分をダブルクリックすると、ダブルクリックした部分を中止に画像が等倍表示されます。再度、ダブルクリックすると、画像は全体表示に戻ります。

 ※ 画像(ファイル名: sample.png サイズ:1920×1080)を同じフォルダ内に準備してください。

<ImageTestWidget>:

    BoxLayout:
        id: box
        size: root.size
        padding: 20
        canvas.before:
            Color:
                rgba: 0.7, 0.7, 0.7, 1
            Rectangle:
                size: self.size
                pos: self.pos

        ScrollView:
            id: scrollview
            size: 640, 360
            do_scroll_x: True
            do_scroll_y: True

            Image:
                id: image
                fit_mode: 'scale-down'
                on_touch_down: root.on_image_down(args[1])
                size_hint: None, None
# -*- coding: utf-8 -*-

import os
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.config import Config
from kivy.properties import ObjectProperty, NumericProperty
from kivy.lang import Builder
from kivy.graphics.texture import Texture
from kivy.core.image import Image as CoreImage

kivy.require('2.2.0')

# 画面サイズの指定
Config.set('graphics', 'width', '680')
Config.set('graphics', 'height', '400')

Builder.load_file(os.path.dirname(__file__) + "/interface.kv")


class ImageTestWidget(Widget):
    state = 0

    def __init__(self, **kwargs):
        super(ImageTestWidget, self).__init__(**kwargs)

        print(self.ids.box.size)

        # 画像ファイルの読み込み
        self.img1 = CoreImage('sample.png')
        # 読み込んだ画像をimageに設定
        self.ids.image.texture = self.img1.texture
        self.ids.image.width = self.ids.scrollview.width
        self.ids.image.height = self.ids.scrollview.height
        self.ids.scrollview.update_from_scroll()

    def on_image_down(self, touch):
        # ダブルクリックであるかの判定
        if touch.is_double_tap:

            if self.state == 0:
                # 等倍表示の処理
                self.ids.image.width = self.ids.image.texture.width
                self.ids.image.height = self.ids.image.texture.height

                # 表示位置の変更
                self.ids.scrollview.update_from_scroll()
                self.ids.scrollview.scroll_x = (
                    touch.pos[0] / self.ids.scrollview.width)
                self.ids.scrollview.scroll_y = (
                    touch.pos[1] / self.ids.scrollview.height)
                self.state = 1
            else:
                # 画面に合わせた表示の処理
                self.ids.image.width = self.ids.scrollview.width
                self.ids.image.height = self.ids.scrollview.height
                self.ids.scrollview.update_from_scroll()
                self.state = 0


class ImageTestWidgetApp(App):
    def __init__(self, **kwargs):
        super(ImageTestWidgetApp, self).__init__(**kwargs)
        self.title = 'Image Test'

    def build(self):
        return ImageTestWidget()


if __name__ == '__main__':
    app = ImageTestWidgetApp()
    app.run()
タイトルとURLをコピーしました