我想创建一个带有图像的按钮网格。每个按钮上的图像都是从较大的图像中切下来的,该图像被切成碎片-因此按钮网格可以看作是原始图像的图块(我用来在按钮上放置图像的代码是from here)
要将图像(image=QPixmap(path_to_image)
)切成碎片,我在for循环中使用了方法image.copy(x, y, width, height)
。
起初,我认为代码可以正常工作。更精确的检查表明图像片段有重叠部分。
这是经过GIF图片测试的代码:
import os
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import \
QWidget, QApplication, \
QGridLayout, \
QLabel, QPushButton
def cut_image_into_tiles(image, rows=4, cols=4) -> dict:
if isinstance(image, str) and os.path.exists(image):
image = QPixmap(image)
elif not isinstance(image, QPixmap):
raise ValueError("image must be str or QPixmap object")
# Dim of the tile
tw = int(image.size().width() / cols)
th = int(image.size().height() / rows)
# prepare return value
tiles = {"width": tw, "height": th}
for r in range(rows):
for c in range(cols):
tile = image.copy(c * th, r * tw, tw, th)
# args: x, y, width, height
# https://doc.qt.io/qt-5/qpixmap.html#copy-1
tiles[(r, c)] = tile
return tiles
def create_pixmapbutton(pixmap, width=0, height=0) -> QPushButton:
if isinstance(pixmap, QPixmap):
button = QPushButton()
if width > 0 and height > 0:
button.setIconSize(QSize(width, height))
else:
button.setIconSize(pixmap.size())
button.setIcon(QIcon(pixmap))
return button
def run_viewer(imagepath, rows=4, cols=4):
# ImageCutter.run_viewer(imagepath)
app = QApplication(sys.argv)
image = QPixmap(imagepath)
tiles = cut_image_into_tiles(image=image, rows=rows, cols=cols)
tilewidth = tiles["width"]
tileheight = tiles["height"]
# get dict tiles (keys:=(row, col) or width or height)
viewer = QWidget()
layout = QGridLayout()
viewer.setLayout(layout)
viewer.setWindowTitle("ImageCutter Viewer")
lbl = QLabel()
lbl.setPixmap(image)
layout.addWidget(lbl, 0, 0, rows, cols)
for r in range(rows):
for c in range(cols):
btn = create_pixmapbutton(
tiles[r, c], width=tilewidth, height=tileheight)
btninfo = "buttonsize={}x{}".format(tilewidth, tileheight)
btn.setToolTip(btninfo)
# logger.debug(" create button [{}]".format(btninfo))
layout.addWidget(btn, r, cols + c)
viewer.show()
sys.exit(app.exec_())
我用run_viewer(path_to_a_gif_image, rows=3, cols=3)
答案 0 :(得分:1)
尝试一下:
import sys
from PyQt5.QtCore import QSize, QRect
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import (QWidget, QApplication, QGridLayout,
QLabel, QPushButton, QSizePolicy)
from PIL import Image
def cut_image_into_tiles(image, r=4, c=4):
im = Image.open(image)
x, y = im.size
for i in range(r):
for j in range(c):
if i!=r and j!=c:
im.crop(box=(x/r*i, y/c*j, x/r*(i+1)-1, y/c*(j+1)-1)).\
save('image{}{}.png'.format(str(i+1), str(j+1)))
def run_viewer(imagepath, rows=4, cols=4):
app = QApplication(sys.argv)
image = QPixmap(imagepath)
tiles = cut_image_into_tiles(image=imagepath, r=rows, c=cols)
viewer = QWidget()
layout = QGridLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
viewer.setLayout(layout)
viewer.setWindowTitle("ImageCutter Viewer")
lbl = QLabel()
lbl.setPixmap(image)
layout.addWidget(lbl, 0, 0, rows, cols)
for r in range(1, rows+1):
for c in range(1, cols+1):
button = QPushButton()
button.setStyleSheet('''QPushButton {background-color: yellow; border: 1px solid black;}
QPushButton:pressed {background-color: green;}''')
image = QPixmap(f"image{c}{r}.png")
button.setIconSize(image.size())
button.setIcon(QIcon(image))
layout.addWidget(button, r-1, c+cols)
viewer.show()
sys.exit(app.exec_())
run_viewer("linux.gif", rows=3, cols=3)
答案 1 :(得分:1)
每个网格的宽度必须取决于图像的宽度,在这种情况下,它取决于th,但是th取决于高度,这是不正确的,您必须将th更改为tw,高度也应更改为相同。
考虑到上述情况,解决方案是:
import os
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QWidget, QApplication, QGridLayout, QLabel, QPushButton
def cut_image_into_tiles(image, rows=4, cols=4) -> dict:
if isinstance(image, str) and os.path.exists(image):
image = QPixmap(image)
elif not isinstance(image, QPixmap):
raise ValueError("image must be str or QPixmap object")
# Dim of the tile
tw = int(image.size().width() / cols)
th = int(image.size().height() / rows)
# prepare return value
tiles = {"width": tw, "height": th}
for r in range(rows):
for c in range(cols):
tile = image.copy(c * tw, r * th, tw, th) # <----
# args: x, y, width, height
# https://doc.qt.io/qt-5/qpixmap.html#copy-1
tiles[(r, c)] = tile
return tiles
def create_pixmapbutton(pixmap, width=0, height=0) -> QPushButton:
if isinstance(pixmap, QPixmap):
button = QPushButton()
if width > 0 and height > 0:
button.setIconSize(QSize(width, height))
else:
button.setIconSize(pixmap.size())
button.setIcon(QIcon(pixmap))
button.setContentsMargins(0, 0, 0, 0)
button.setFixedSize(button.iconSize())
return button
def run_viewer(imagepath, rows=4, cols=4):
# ImageCutter.run_viewer(imagepath)
app = QApplication(sys.argv)
image = QPixmap(imagepath)
tiles = cut_image_into_tiles(image=image, rows=rows, cols=cols)
tilewidth = tiles["width"]
tileheight = tiles["height"]
# get dict tiles (keys:=(row, col) or width or height)
viewer = QWidget()
layout = QGridLayout(viewer)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
viewer.setWindowTitle("ImageCutter Viewer")
lbl = QLabel()
lbl.setPixmap(image)
layout.addWidget(lbl, 0, 0, rows, cols)
for r in range(rows):
for c in range(cols):
btn = create_pixmapbutton(tiles[r, c], width=tilewidth, height=tileheight)
btninfo = "buttonsize={}x{}".format(tilewidth, tileheight)
btn.setToolTip(btninfo)
# logger.debug(" create button [{}]".format(btninfo))
layout.addWidget(btn, r, cols + c)
viewer.show()
viewer.setFixedSize(viewer.sizeHint())
sys.exit(app.exec_())
run_viewer("linux.gif", 3, 3)
答案 2 :(得分:0)
好吧,我发现对于大图像和大网格,右侧按钮上的图像可以小于其他按钮。底部按钮相同。
顶部和左侧的偏移量可以防止这种情况。
因此,函数def cut_image_into_tiles(image, rows=4, cols=4) -> dict:
必须适用于:
def cut_image_into_tiles(image, rows=4, cols=4) -> dict:
if isinstance(image, str) and os.path.exists(image):
image = QPixmap(image)
elif not isinstance(image, QPixmap):
raise ValueError("image must be str or QPixmap object")
# Dim of tiled images
width = image.size().width()
height = image.size().height()
tw = int(width / cols)
th = int(height / rows)
offset_w = int((width - tw * cols)/2) # !!!
offset_h = int((height - th * rows)/2) # !!!
# prepare return value
tiles = {"width": tw, "height": th}
for r in range(rows):
for c in range(cols):
x = c * tw
y = r * th
if c == 0:
x += offset_w # !!!
if r == 0:
y += offset_h # !!!
tile = image.copy(x, y, tw, th)
# args: x, y, width, height
# https://doc.qt.io/qt-5/qpixmap.html#copy-1
tiles[(r, c)] = tile
return tiles
整个代码现在是:
def cut_image_into_tiles(image, rows=4, cols=4) -> dict:
if isinstance(image, str) and os.path.exists(image):
image = QPixmap(image)
elif not isinstance(image, QPixmap):
raise ValueError("image must be str or QPixmap object")
# Dim of tiled images
width = image.size().width()
height = image.size().height()
tw = int(width / cols)
th = int(height / rows)
offset_w = int((width - tw * cols)/2)
offset_h = int((height - th * rows)/2)
# prepare return value
tiles = {"width": tw, "height": th}
for r in range(rows):
for c in range(cols):
x = c * tw
y = r * th
if c == 0:
x += offset_w
if r == 0:
y += offset_h
tile = image.copy(x, y, tw, th)
# args: x, y, width, height
# https://doc.qt.io/qt-5/qpixmap.html#copy-1
tiles[(r, c)] = tile
return tiles
def create_pixmapbutton(pixmap, width=0, height=0) -> QPushButton:
if isinstance(pixmap, QPixmap):
button = QPushButton()
if width > 0 and height > 0:
button.setIconSize(QSize(width, height))
else:
button.setIconSize(pixmap.size())
button.setIcon(QIcon(pixmap))
return button
def run_viewer(imagepath, rows=4, cols=4):
# ImageCutter.run_viewer(imagepath)
app = QApplication(sys.argv)
image = QPixmap(imagepath)
tiles = cut_image_into_tiles(image=image, rows=rows, cols=cols)
tilewidth = tiles["width"]
tileheight = tiles["height"]
# get dict tiles (keys:=(row, col) or width or height)
viewer = QWidget()
layout = QGridLayout()
viewer.setLayout(layout)
viewer.setWindowTitle("ImageCutter Viewer")
lbl = QLabel()
lbl.setPixmap(image)
layout.addWidget(lbl, 0, 0, rows, cols)
for r in range(rows):
for c in range(cols):
btn = create_pixmapbutton(
tiles[r, c], width=tilewidth, height=tileheight)
btninfo = "buttonsize={}x{}".format(tilewidth, tileheight)
btn.setToolTip(btninfo)
# logger.debug(" create button [{}]".format(btninfo))
layout.addWidget(btn, r, cols + c)
viewer.show()
sys.exit(app.exec_())