QPainterで画像合成してWidgetに表示する方法!!

takkun
どうも!たっくんです!

サムネイルなどを表示するツールを作っていると、一時的に画像を合成したい時ってございませんか!?フレームや、ステータスなど情報がわかりやすくなる画像を合成してあげると合成してあげると、ぐっと視認性がよくなりますよね(*´ω`*)

今回は、Qt(PySide/PyQt)の機能だけを使って一時的に画像を合成して表示する方法をご紹介したいと思います!(`・ω・´)ゞ

PySideのUIに画像を表示する方法!!

2017.08.16

クラスの骨格

QLabelを継承したクラス「CombineImage」の骨格を用意します。引数で画像を2つ指定できるようにしておきます!

from PySide import QtCore, QtGui

class CombineImage(QtGui.QLabel):
	def __init__(self, srcImagePath=None, dstImagePath=None, parent=None):
		super(CombineImage, self).__init__(parent)

合成の準備

指定された画像のパスから「QImage」のインスタンスを作成し、合成した結果を入れるための「QImage」と、画像を合成するための「QPainter」のインスタンスを用意します!

from PySide import QtCore, QtGui

class CombineImage(QtGui.QLabel):
	def __init__(self, srcImagePath=None, dstImagePath=None, parent=None):
		super(CombineImage, self).__init__(parent)
		
		# 指定された画像のパスからQImageのインスタンスを作成
		srcImage = QtGui.QImage(srcImagePath)
		dstImage = QtGui.QImage(dstImagePath)
		
		# 合成した結果を入れるためのQImageのインスタンスを作成
		resultImage = QtGui.QImage(
						srcImage.width(),
						srcImage.height(),
						QtGui.QImage.Format_ARGB32_Premultiplied
						)
		
		# QPainterのインスタンスを作成
		painter = QtGui.QPainter(resultImage)

QPainterを経由して画像を合成する

合成した結果を入れるための「QImage」に、「QPainter」を経由して画像を書き込んでいきます!

from PySide import QtCore, QtGui

class CombineImage(QtGui.QLabel):
	def __init__(self, srcImagePath=None, dstImagePath=None, parent=None):
		super(CombineImage, self).__init__(parent)
		srcImage = QtGui.QImage(srcImagePath)
		dstImage = QtGui.QImage(dstImagePath)
		resultImage = QtGui.QImage(
						srcImage.width(),
						srcImage.height(),
						QtGui.QImage.Format_ARGB32_Premultiplied
						)
		painter = QtGui.QPainter(resultImage)
		
		# 透明で塗りつぶし
		painter.fillRect(resultImage.rect(), QtCore.Qt.transparent)
		
		# srcImageを空の画像に描画
		painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
		painter.drawImage(0, 0, srcImage)
		
		# dstImageを空の画像に描画
		painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
		painter.drawImage(0, 0, dstImage)

		# QPainterの終了
		painter.end()

合成した画像をWidgetに設定設定

合成した画像は「QImage」で出来ているので、「QPixmap」に変換して「QLabelのsetPixmap」を経由してWidgetに設定します。

from PySide import QtCore, QtGui

class CombineImage(QtGui.QLabel):
	def __init__(self, srcImagePath=None, dstImagePath=None, parent=None):
		super(CombineImage, self).__init__(parent)
		srcImage = QtGui.QImage(srcImagePath)
		dstImage = QtGui.QImage(dstImagePath)
		resultImage = QtGui.QImage(
						srcImage.width(),
						srcImage.height(),
						QtGui.QImage.Format_ARGB32_Premultiplied
						)
		painter = QtGui.QPainter(resultImage)
		painter.fillRect(resultImage.rect(), QtCore.Qt.transparent)
		
		painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
		painter.drawImage(0, 0, srcImage)
		
		painter.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
		painter.drawImage(0, 0, dstImage)

		painter.end()
		
		# 合成した画像をQPixmapに変換して、自身に設定
		self.setPixmap(QtGui.QPixmap.fromImage(resultImage))

表示のテスト!

以下のコードを使用して、画像を表示してみます!

window = QtGui.QWidget()
window.setWindowFlags(QtCore.Qt.Window)
window.resize(200, 200)
layout = QtGui.QHBoxLayout(window)
layout.addWidget(CombineImage(r'D:\image_00.png', r'D:\image_01.png'))
window.show()

早速実行してみると、、、2つの画像が合成されて表示できるようになりました!

実際、毎回合成していては処理時間や、サーバーなどへのアクセス頻度が高すぎると思うので、合成が終った「QImage」の「save」を使ってファイルに保存してキャッシュを作ると負荷が軽減できると思います!