[ todo ] PyQt で画像のビューアを作る version 36
[ todo ] PyQt で画像のビューアを作る
      @[TOC](項目)
----------------
# Qt でグラディエーション
- クラス作るか
まず描画できるかどうかだけ試してみよう
- スライダー三つ、ラベルとスピンボックス付き
```
from PyQt5.QtGui import QPainter , QRadialGradient , QBrush , QColor
class DrawGrad():
 def __init__(self,p,l) # p:parent  l:label_5
  self.p = p # parent
  self.label=l # label
  self.pix=l.pixmap(l)
  self.x = l.width()/2   # center of circle
  self.y = l.height()/2
  self.r = l.width()/2    # 半径
  self.xx = self.x    # center of grad
  self.yy = self.y    # center of grad
  # スライダーの設定、range,position connect
  p.ui.slide_****.setRange (0, l.width() )
  p.ui.slide_****.setSliderPosition ( self.x )
  p.ui.slide_****.valueChanged[int].connect ( self.param )
 def param(self,v): # コネクトの受け
    if not self.p.radiobutton_1.isChecked() :
        return
  if self.sender() == self.p.ui.*******
   self.x = v
  elif self.sender() == self.p.ui.*******
   self.y = v
  elif self.sender() == self.p.ui.*******
   self.r = v
  self.draw()
 def draw(self):
    if not self.p.radiobutton_1.isChecked() :
        return
    paint=QPainter()
    paint.begin( self.pix ) # <----
    grad = QRadialGradient( self.x , self.y , sef.r , self.xx , self.yy) 
    # grad = QRadialGradient(150,50,50,160,60) #(150,50)を中心、半径50、(160,60)が開始位置
    grad.setColorAt(0.0, Qg.QColor(Qt.white))   #色を指定
    grad.setColorAt(1.0, Qg.QColor(Qt.black))
    paint.setBrush(Qg.QBrush(grad))            #画面への描画
    paint.drawRect(0,0, self.label.width() , self.label.height() )
    paint.end()
    self.l.show()
    # self.p. <----------  右側の再描画 ルーチンを本体で作る
    # label_5.pixmap().save(device , 'BMP')    って感じかな?
    # そのあとpillowで読み込んで self.mask にセットする
```
円のグラデだが、中心をずらせるんだなあ
①ラジオでマスク表示モードに入る
②まずは円形グラデだけ、白から黒だけ
③スライダを縦横用意して、中心点を設定(デフォルトは画像の中心)
 中心点は赤で描画
④開始点をスライダーで
⑤終了点をスライダーで
⑥関数は一つ、senderでスライダー値を分岐させる
⑦スライダー値はselfで保存、リセットボタンも必要だな
----
PyQtでお手軽GUI開発♪―――は可能だったか? 第4回 画面描画編 
http://www7a.biglobe.ne.jp/~thor/novel/column/07.html
```
def paintEvent(self, event):
    canvas = Qg.QPainter(self)                  #画面のPainterを取得する
    #線形グラデーション
    grad = Qg.QLinearGradient(25,0,75,100)      #座標(25,0)~(75,100)間で定義
    grad.setColorAt(0.1, Qg.QColor(Qt.red))     #色の位置の設定
    grad.setColorAt(0.5, Qg.QColor(Qt.green))
    grad.setColorAt(1.0, Qg.QColor(Qt.blue))
    canvas.setBrush(Qg.QBrush(grad))            #画面に描画する
    canvas.drawRect(0,0,100,100)
    #放射状グラデーション
    grad = Qg.QRadialGradient(150,50,50,160,60) #(150,50)を中心、半径50、(160,60)が開始位置
    grad.setColorAt(0.0, Qg.QColor(Qt.white))   #色を指定
    grad.setColorAt(1.0, Qg.QColor(Qt.blue))
    canvas.setBrush(Qg.QBrush(grad))            #画面への描画
    canvas.drawRect(100,0,100,100)
    #円錐形グラデーション
    grad = Qg.QConicalGradient(250, 50, 45)     #座標(250,50)を中心に45度角から開始
    grad.setColorAt(0.0, Qg.QColor(Qt.red))     #色の指定
    grad.setColorAt(0.33, Qg.QColor(Qt.green))
    grad.setColorAt(0.66, Qg.QColor(Qt.blue))
    grad.setColorAt(1.0, Qg.QColor(Qt.red))
    canvas.setBrush(Qg.QBrush(grad))            #画面への描画
    canvas.drawRect(200,0,100,100)
```
-------------------------------------
# ペンの色を指定
```
23.    painter.setPen(Qt.red)
24.    #painter.setPen(QColor(255, 0, 0))
26.    # 使用するフォントを指定
27.    painter.setFont(QFont('Times', 30))
28.    # テキスト描画
29.    painter.drawText(image.rect(), Qt.AlignCenter, 'Symfoware')
30.    # 画像の編集終了
31.    painter.end()
```
----
- コンテキストメニューを作るか
結構長くなるから別ファイルにしておくか??
このソフトの機能を呼び出すときの主要な手段になるよな
- コメント表示したい
- マウスジェスチャ 軌跡の表示
自作ものはジェスチャとコマンドが画像中心に表示される仕様だった
ウインドウを出してたんだな
別に無くても良いんだけど・・・・
- zip内の画像を順に表示できるようにする
一覧、スプレッドシートも必要
リストビューに画像表示させれば良いのかな
自作もののソースを見るか?
- 編集機能はどうしよう
回転は欲しいような気もするが
色調補正は別ソフトじゃ無きゃだめなような・・・
8bfをpythonから使えないかな???
-------------------------------------------------------------
--------------------------------------
# 画像への文字や矩形表示について調べた
- HTMLとしてラベルに表示するやり方があるようだ
http://blog.shibu.jp/article/60706676.html
----
# コンテキストメニュー
考えたら右クリックにはジェスチャを設定していたから普通にコンテキストメニューを使うと反応してしまう
```
def mouseReleaseEvent(self,e)
 if self.ges['cmd'] == '' : # ジェスチャが無い場合はコンテキストメニューを出す
   c_menu.cmenu(e)
 else :
   元のコード
========================================
<< 本体ファイル >>
from PyQt5.QtCore import  Qt 
from custommenu.py import c_menu
__init__
 c_menu(self)
 self.label.setContextMenuPolicy(Qt.CustomContextMenu)
 self.label.customContextMenuRequested.connect(c_menu.cmenu)
label か mainwindow か???
<< 別ファイルで  custommenu.py >>
from PyQt5.QtWidgets import  QAction ,QMenu 
class c_menu():
 def __init__(self,p) :
  self.parent = p
 def c_menu(self,e): # e が来るのかな??
  menu=QMenu(self.parent)
  action = QAction('Open Folder', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)
  action = QAction('AddToList', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)
  # menu.exec_(QCursor.pos ())   
  menu.exec_( e )   
```
----
# zip内の画像を順に表示できるようにする
- 結構面倒だよ
とりあえずキーイベントで動作させよう
```
# self.pics=[]  これやめよう
def __init__
 self.current={'pics':[] , 'index':0, 'picslen':0 ,'zipflag':0 }
 self.zip={ 'pics':[] , 'index':0, 'picslen':0}
※このあとで self.pics は全て書き換えること(ここを含めて全8箇所)
def wheel の最後で
 showzip(1) # zip 初期化
 self.current['zipflag'] = 0  or 1
def keyPressEvent (self, e):
 if self.current['zipflag'] :
  if e.key()==Qt.Key_Down :
   self.calcnext( 'inc' )
  if e.key()==Qt.Key_Up :
   self.calcnext( 'dec' )
  showzip(0) # 既存    
  # zipでなければ無視
def showzip( self ,flag ):  # ここは書き換え
        zi = ZipFile( self.current['pics'][self.current['index'] ] , 'r' )
        if flag :
            self.zip['pics'].clear()
            self.zip['pics'] = zi.namelist()
            self.zip['picslen'] = len( self.zip['pics'] )
            self.zip['index'] = 0
        with zi.open( self.zip['pics'][ self.zip['index'] ] ) as z_image :
            pix = QPixmap()    # ここスワップした方が良いのかな
            pix.loadFromData(z_image.read())
            self.label.setPixmap(pix)
            self.resize(pix.width(),pix.height())
            self.show()
        zi.close()
<< サイクル計算するルーチン >>
def calcnext( sign ) :# 増か減か
 if self.current['zipflag'}:
  index = self.zip['index']
  len = self.zip['picslen']
 else:
  index = self.current['index']
  len = self.current['picslen']
 if sign == 'inc':
  index += 1
  if index > (len-1) :
   index=0
 elif sign == 'dec' :
  index -= 1
  if index < 0:
   index = len-1
 if self.current['zipflag'}:
  self.zip['index'] = index
 else:
  self.current['index'] = index
```
- 三項演算子
x = "OK" if n == 10 else "NG"
こうやって書けるのかな?
 if sign == 'inc':
  index = index+1  if index < len-1  else  0
 elif sign == 'dec' :
  index = index-1  if index => 0  else  len-1
---
# UIの検討
①pngでアルファを持ったグラデ画像を作る
②二画面表示にして左がオリジナル、右が変換後
③左をマスクと切り替えできるようにラジオをつける
④右は常に原画にかぶせるが、ラジオでマスクの適用を切り替える
----
# 勉強サイト
- JPEGファイルの構造
https://hp.vector.co.jp/authors/VA032610/JPEGFormat/StructureOfJPEG.htm
- PNG ファイルフォーマット
https://www.setsuki.com/hsp/ext/png.htm
- Qtで始める画像処理
https://qiita.com/kanryu/items/89812b362dfd581a4c10
ここ面白そう、読もう
----
[目次に戻る](https://mimemo.io/m/QORbW4qkvOoda0N)
      
    
  項目Qt でグラディエーションペンの色を指定画像への文字や矩形表示について調べたコンテキストメニューzip内の画像を順に表示できるようにするUIの検討勉強サイト
Qt でグラディエーション
- クラス作るか
まず描画できるかどうかだけ試してみよう - スライダー三つ、ラベルとスピンボックス付き
 
from PyQt5.QtGui import QPainter , QRadialGradient , QBrush , QColor
class DrawGrad():
 def __init__(self,p,l) # p:parent  l:label_5
  self.p = p # parent
  self.label=l # label
  self.pix=l.pixmap(l)
  self.x = l.width()/2   # center of circle
  self.y = l.height()/2
  self.r = l.width()/2    # 半径
  self.xx = self.x    # center of grad
  self.yy = self.y    # center of grad
  # スライダーの設定、range,position connect
  p.ui.slide_****.setRange (0, l.width() )
  p.ui.slide_****.setSliderPosition ( self.x )
  p.ui.slide_****.valueChanged[int].connect ( self.param )
 def param(self,v): # コネクトの受け
    if not self.p.radiobutton_1.isChecked() :
        return
  if self.sender() == self.p.ui.*******
   self.x = v
  elif self.sender() == self.p.ui.*******
   self.y = v
  elif self.sender() == self.p.ui.*******
   self.r = v
  self.draw()
 def draw(self):
    if not self.p.radiobutton_1.isChecked() :
        return
    paint=QPainter()
    paint.begin( self.pix ) # <----
    grad = QRadialGradient( self.x , self.y , sef.r , self.xx , self.yy) 
    # grad = QRadialGradient(150,50,50,160,60) #(150,50)を中心、半径50、(160,60)が開始位置
    grad.setColorAt(0.0, Qg.QColor(Qt.white))   #色を指定
    grad.setColorAt(1.0, Qg.QColor(Qt.black))
    paint.setBrush(Qg.QBrush(grad))            #画面への描画
    paint.drawRect(0,0, self.label.width() , self.label.height() )
    paint.end()
    self.l.show()
    # self.p. <----------  右側の再描画 ルーチンを本体で作る
    # label_5.pixmap().save(device , 'BMP')    って感じかな?
    # そのあとpillowで読み込んで self.mask にセットする
円のグラデだが、中心をずらせるんだなあ
①ラジオでマスク表示モードに入る
②まずは円形グラデだけ、白から黒だけ
③スライダを縦横用意して、中心点を設定(デフォルトは画像の中心)
 中心点は赤で描画
④開始点をスライダーで
⑤終了点をスライダーで
⑥関数は一つ、senderでスライダー値を分岐させる
⑦スライダー値はselfで保存、リセットボタンも必要だな
PyQtでお手軽GUI開発♪―――は可能だったか? 第4回 画面描画編
http://www7a.biglobe.ne.jp/~thor/novel/column/07.html
def paintEvent(self, event):
    canvas = Qg.QPainter(self)                  #画面のPainterを取得する
    #線形グラデーション
    grad = Qg.QLinearGradient(25,0,75,100)      #座標(25,0)~(75,100)間で定義
    grad.setColorAt(0.1, Qg.QColor(Qt.red))     #色の位置の設定
    grad.setColorAt(0.5, Qg.QColor(Qt.green))
    grad.setColorAt(1.0, Qg.QColor(Qt.blue))
    canvas.setBrush(Qg.QBrush(grad))            #画面に描画する
    canvas.drawRect(0,0,100,100)
    #放射状グラデーション
    grad = Qg.QRadialGradient(150,50,50,160,60) #(150,50)を中心、半径50、(160,60)が開始位置
    grad.setColorAt(0.0, Qg.QColor(Qt.white))   #色を指定
    grad.setColorAt(1.0, Qg.QColor(Qt.blue))
    canvas.setBrush(Qg.QBrush(grad))            #画面への描画
    canvas.drawRect(100,0,100,100)
    #円錐形グラデーション
    grad = Qg.QConicalGradient(250, 50, 45)     #座標(250,50)を中心に45度角から開始
    grad.setColorAt(0.0, Qg.QColor(Qt.red))     #色の指定
    grad.setColorAt(0.33, Qg.QColor(Qt.green))
    grad.setColorAt(0.66, Qg.QColor(Qt.blue))
    grad.setColorAt(1.0, Qg.QColor(Qt.red))
    canvas.setBrush(Qg.QBrush(grad))            #画面への描画
    canvas.drawRect(200,0,100,100)
ペンの色を指定
23.    painter.setPen(Qt.red)
24.    #painter.setPen(QColor(255, 0, 0))
26.    # 使用するフォントを指定
27.    painter.setFont(QFont('Times', 30))
28.    # テキスト描画
29.    painter.drawText(image.rect(), Qt.AlignCenter, 'Symfoware')
30.    # 画像の編集終了
31.    painter.end()
- 
コンテキストメニューを作るか
結構長くなるから別ファイルにしておくか??
このソフトの機能を呼び出すときの主要な手段になるよな - 
コメント表示したい
 - 
マウスジェスチャ 軌跡の表示
自作ものはジェスチャとコマンドが画像中心に表示される仕様だった
ウインドウを出してたんだな
別に無くても良いんだけど・・・・ - 
zip内の画像を順に表示できるようにする
一覧、スプレッドシートも必要
リストビューに画像表示させれば良いのかな
自作もののソースを見るか? - 
編集機能はどうしよう
回転は欲しいような気もするが
色調補正は別ソフトじゃ無きゃだめなような・・・
8bfをpythonから使えないかな??? 
画像への文字や矩形表示について調べた
- HTMLとしてラベルに表示するやり方があるようだ
http://blog.shibu.jp/article/60706676.html 
コンテキストメニュー
考えたら右クリックにはジェスチャを設定していたから普通にコンテキストメニューを使うと反応してしまう
def mouseReleaseEvent(self,e)
 if self.ges['cmd'] == '' : # ジェスチャが無い場合はコンテキストメニューを出す
   c_menu.cmenu(e)
 else :
   元のコード
========================================
<< 本体ファイル >>
from PyQt5.QtCore import  Qt 
from custommenu.py import c_menu
__init__
 c_menu(self)
 self.label.setContextMenuPolicy(Qt.CustomContextMenu)
 self.label.customContextMenuRequested.connect(c_menu.cmenu)
label か mainwindow か???
<< 別ファイルで  custommenu.py >>
from PyQt5.QtWidgets import  QAction ,QMenu 
class c_menu():
 def __init__(self,p) :
  self.parent = p
 def c_menu(self,e): # e が来るのかな??
  menu=QMenu(self.parent)
  action = QAction('Open Folder', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)
  action = QAction('AddToList', self.parent)
  action.triggered.connect(self.parent.**** )
  menu.addAction(action)
  # menu.exec_(QCursor.pos ())   
  menu.exec_( e )   
zip内の画像を順に表示できるようにする
- 結構面倒だよ
とりあえずキーイベントで動作させよう 
# self.pics=[]  これやめよう
def __init__
 self.current={'pics':[] , 'index':0, 'picslen':0 ,'zipflag':0 }
 self.zip={ 'pics':[] , 'index':0, 'picslen':0}
※このあとで self.pics は全て書き換えること(ここを含めて全8箇所)
def wheel の最後で
 showzip(1) # zip 初期化
 self.current['zipflag'] = 0  or 1
def keyPressEvent (self, e):
 if self.current['zipflag'] :
  if e.key()==Qt.Key_Down :
   self.calcnext( 'inc' )
  if e.key()==Qt.Key_Up :
   self.calcnext( 'dec' )
  showzip(0) # 既存    
  # zipでなければ無視
def showzip( self ,flag ):  # ここは書き換え
        zi = ZipFile( self.current['pics'][self.current['index'] ] , 'r' )
        if flag :
            self.zip['pics'].clear()
            self.zip['pics'] = zi.namelist()
            self.zip['picslen'] = len( self.zip['pics'] )
            self.zip['index'] = 0
        with zi.open( self.zip['pics'][ self.zip['index'] ] ) as z_image :
            pix = QPixmap()    # ここスワップした方が良いのかな
            pix.loadFromData(z_image.read())
            self.label.setPixmap(pix)
            self.resize(pix.width(),pix.height())
            self.show()
        zi.close()
<< サイクル計算するルーチン >>
def calcnext( sign ) :# 増か減か
 if self.current['zipflag'}:
  index = self.zip['index']
  len = self.zip['picslen']
 else:
  index = self.current['index']
  len = self.current['picslen']
 if sign == 'inc':
  index += 1
  if index > (len-1) :
   index=0
 elif sign == 'dec' :
  index -= 1
  if index < 0:
   index = len-1
 if self.current['zipflag'}:
  self.zip['index'] = index
 else:
  self.current['index'] = index
- 三項演算子
x = "OK" if n == 10 else "NG" 
こうやって書けるのかな?
if sign == 'inc':
index = index+1  if index < len-1  else  0
elif sign == 'dec' :
index = index-1  if index => 0  else  len-1
UIの検討
①pngでアルファを持ったグラデ画像を作る
②二画面表示にして左がオリジナル、右が変換後
③左をマスクと切り替えできるようにラジオをつける
④右は常に原画にかぶせるが、ラジオでマスクの適用を切り替える
勉強サイト
- JPEGファイルの構造
https://hp.vector.co.jp/authors/VA032610/JPEGFormat/StructureOfJPEG.htm - PNG ファイルフォーマット
https://www.setsuki.com/hsp/ext/png.htm - Qtで始める画像処理
https://qiita.com/kanryu/items/89812b362dfd581a4c10
ここ面白そう、読もう