def save_image_to(self, path): TOP_MARGIN = 50 LEFT_MARGIN = 50 # Determine the size of the entire graph graph_size = self._graph_size() image_size = QSize(graph_size.width() + LEFT_MARGIN * 2, graph_size.height() + TOP_MARGIN * 2 ) image = QImage(image_size, QImage.Format_ARGB32) image.fill(Qt.white) # white background painter = QPainter(image) painter.translate(TOP_MARGIN, LEFT_MARGIN) painter.setRenderHint(QPainter.TextAntialiasing) self._paint(painter, QPoint(-TOP_MARGIN, -LEFT_MARGIN), QPoint(image_size.width(), image_size.height()) ) painter.end() image.save(path)
def save_image_to(self, path, top_margin=50, bottom_margin=50, left_margin=50, right_margin=50): margins = QMarginsF(left_margin, top_margin, right_margin, bottom_margin) oldRect = self.scene().sceneRect() minRect = self.scene().itemsBoundingRect() imgRect = minRect.marginsAdded(margins) image = QImage(imgRect.size().toSize(), QImage.Format_ARGB32) image.fill(Qt.white) painter = QPainter(image) painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing) # draw the image self.scene().setSceneRect(imgRect) self.scene().render(painter) image.save(path) # cleanup painter.end() # restore the old scene rect self.scene().setSceneRect(oldRect)
def encode_image(image: QImage) -> str: image_bytes = QByteArray() buffer = QBuffer(image_bytes) buffer.open(QIODevice.WriteOnly) # writes pixmap into bytes in PNG format image.save(buffer, "PNG") # type: ignore encoded_bytes = image_bytes.toBase64() codec = QTextCodec.codecForName(b"UTF-8") encoded_string = codec.toUnicode(encoded_bytes) return encoded_string
def dropEvent(self, event): data = event.mimeData() if event.mimeData().hasImage(): image = QImage(event.mimeData().imageData()) self.filepath = f"{os.getcwd()}/cache/{str(uuid.uuid4())}.jpg" image.save(self.filepath) return urls = data.urls() if urls and urls[0].scheme() == 'file': # for some reason, this doubles up the intro slash self.filepath = str(urls[0].path())[1:]
def paste(self): clipboard = QApplication.clipboard() data = clipboard.mimeData() if data.hasImage(): image = QImage(data.imageData()) try: self.protocol.file_to_send = f"{os.getcwd()}/cache/{str(uuid.uuid4())}.jpg" except AttributeError: return image.save(self.protocol.file_to_send) elif data.hasText(): self.message_input.insert(data.text())
def testImage(): width, height = 100, 100 im = QImage(width, height, QImage.Format_ARGB32) for x in range(im.width()): for y in range(im.height()): if x % 2 == 0: im.setPixel(x, y, QColor('white').rgb()) else: im.setPixel(x, y, QColor('black').rgb()) # im.setPixel(x, y, QColor(255, x*2.56, y*2.56, 255).rgb()) im.save('test.png')
def qt_image_to_array(qimage: QtGui.QImage) -> np.ndarray: """ Convert qimage to numpy array Code adapted from SO: https://stackoverflow.com/a/1756587/7330813 """ bio = io.BytesIO() bfr = QtCore.QBuffer() bfr.open(QtCore.QIODevice.ReadWrite) qimage.save(bfr, 'PNG') bytearr = bfr.data() bio.write(bytearr.data()) bfr.close() bio.seek(0) img = Image.open(bio) return np.array(img)
def generate(self, voter_num): if not isdir(self.details.output_dir): makedirs(self.details.output_dir) sizes = ScoreboardSizes(self.details, self.fonts, voter_num) image = QImage(sizes.width, sizes.height, QImage.Format_ARGB32) painter = QPainter() painter.begin(image) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.TextAntialiasing, True) self._draw_scoreboard(painter, sizes, voter_num) painter.end() output_file_path = sanitize_filename("{} – {}.png".format( voter_num + 1, self.contest.voters[voter_num])) image.save(join(self.details.output_dir, output_file_path))
class QMoon(QWidget): """Small widget displays today's moon.""" def __init__(self, pos=(0, 0), parent=None, size=216, web=False, save=False, debug=0): super(QMoon, self).__init__(parent) self.total_images = 8760 self.moon_domain = "https://svs.gsfc.nasa.gov" self.moon_path_2021 = "/vis/a000000/a004800/a004874/" # https://svs.gsfc.nasa.gov/vis/a000000/a004900/a004955/frames/216x216_1x1_30p/moon.8597.jpg self.moon_path = "/vis/a000000/a004900/a004955/" self.debug = debug self.size = size self.get_from_web = web self.save = save # self.setGeometry(pos[0], pos[1], self.size, self.size) self.moon = QLabel(self) self.moon.setGeometry(pos[0], pos[1], self.size, self.size) self.update() self.timer = QTimer(self) self.timer.timeout.connect(self.update) self.timer.start(3600 * 1000) self.image = None self.pixmap = None self.moon_image_number = 1 @Slot() def update(self): if self.debug > 0: print("Updating the Moon Phase pixmap.") self.pixmap = self.get_moon_image() self.moon.setPixmap(self.pixmap) def get_moon_image_number(self): # # Conversion from the jscript. # now = datetime.utcnow() janone = datetime(now.year, 1, 1, 0, 0, 0) self.moon_image_number = round( (datetime.utcnow() - janone).total_seconds() / 3600) return self.moon_image_number <= self.total_images def get_moon_image(self): if not self.get_moon_image_number(): print("Could not get the moon. Are we in a new year?") if self.debug: print(f"We are using moon image number: {self.moon_image_number}") if self.size > 500 or self.get_from_web: if self.size > 2160: url = self.moon_domain+self.moon_path+"/frames/5760x3240_16x9_30p/" \ f"plain/moon.{self.moon_image_number:04d}.tif" elif self.size > 216: url = self.moon_domain+self.moon_path+"/frames/3840x2160_16x9_30p/" \ f"plain/moon.{self.moon_image_number:04d}.tif" else: url = self.moon_domain + self.moon_path + "/frames/216x216_1x1_30p/" \ f"moon.{self.moon_image_number:04d}.jpg" if self.debug: print(f"Getting image from url: {url}") req = requests.get(url) self.image = QImage() self.image.loadFromData(req.content, "tiff") size = self.image.size() if self.debug: print("Image size: ", size) if self.save: self.image.save(f"moon/moon.{self.moon_image_number:04d}.tiff") offset = (size.width() - size.height()) / 2 rect = QRect(offset, 0, size.height(), size.height()) self.image = self.image.copy(rect) pix = QPixmap.fromImage(self.image) pix = pix.scaled(self.size, self.size, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) return pix else: moon_file = f"moon/moon.{self.moon_image_number:04d}.jpg" pix = QPixmap(moon_file) pix = pix.scaled(self.size, self.size, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) return pix
class Picture(object): def __init__(self, path): super(Picture, self).__init__() self.path = path self.name = self.path.split("/")[-1] self.extension = os.path.splitext(self.path)[1] self.scale = 1.0 self.image = QImage(self.path) self.thumbnail = self.image.scaled(QSize(110, 110), aspectMode=Qt.KeepAspectRatio, mode=Qt.SmoothTransformation) self.resolution = "Resolution: " + str(self.image.width()) + "x" + str( self.image.height()) + "px" def deletePicture(self): os.remove(self.path) def verticalFlip(self): self.image = self.image.mirrored(vertically=True, horizontally=False) self.thumbnail = self.image.scaled(QSize(110, 110), aspectMode=Qt.KeepAspectRatio, mode=Qt.SmoothTransformation) self.image.save(self.path) def horizontalFlip(self): self.image = self.image.mirrored(horizontally=True, vertically=False) self.thumbnail = self.image.scaled(QSize(110, 110), aspectMode=Qt.KeepAspectRatio, mode=Qt.SmoothTransformation) self.image.save(self.path) def zoomIn(self): self.scale = self.scale * 0.9 def zoomOut(self): self.scale = self.scale * 1.1 def rotateCW(self): transform = QTransform() transform.translate(self.image.width() / 2, self.image.height() / 2) transform.rotate(90) self.image = self.image.transformed(transform) self.image.save(self.path) self.thumbnail = self.image.scaled(QSize(110, 110), aspectMode=Qt.KeepAspectRatio, mode=Qt.SmoothTransformation) def rotateCCW(self): transform = QTransform() transform.translate(self.image.width() / 2, self.image.height() / 2) transform.rotate(-90) self.image = self.image.transformed(transform) self.image.save(self.path) self.thumbnail = self.image.scaled(QSize(110, 110), aspectMode=Qt.KeepAspectRatio, mode=Qt.SmoothTransformation) def saveImage(self): self.image.save(self.path)
class Mainwindow(QWidget): def __init__(self): super().__init__() self.setupUI() self.setupCamera() self.window.show() def setupUI(self): # 載入ui檔"mainwindow.ui" path = os.path.join(os.path.dirname(__file__), "mainwindow.ui") uiFile = QFile(path) uiFile.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(uiFile) uiFile.close() # 設定widget # 所有widget都要在前面加上self 否則其他function無法使用那個widget # 顯示攝影機畫面 self.imageLabel = self.window.findChild(QLabel, 'imageLabel') # 按一下拍照 將畫面定格 self.btn_takePict = self.window.findChild(QPushButton, 'btn_takePict') self.btn_takePict.clicked.connect(self.takePicture) # 按一下取消畫面定格 self.btn_cancelTakePict = self.window.findChild( QPushButton, 'btn_cancelTakePict') self.btn_cancelTakePict.clicked.connect(self.cancelTakePicture) # 按一下把臉上的眼鏡清空 self.btn_revert = self.window.findChild(QPushButton, 'btn_revert') self.btn_revert.clicked.connect(self.revert) # 提示user按下拍照件 並在拍照後顯示user臉型 self.faceshapeOfUser = self.window.findChild(QTextBrowser, "faceshapeOfUser") self.faceshapeOfUser.setText("按下拍照來確認自己臉型") # 按下拍照後 會顯示適合的眼鏡 依照眼鏡類型分類 self.tabWidget = self.window.findChild(QTabWidget, "tabWidget") self.numOfTab = 0 def setupCamera(self): # 打開鏡頭 self.capture = cv2.VideoCapture(0) # 設定大小 self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, 600) self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 500) # 顯示畫面 self.timer = QTimer() self.timer.timeout.connect(self.displayVideoStream) self.timer.start(30) def displayVideoStream(self): _, frame = self.capture.read() frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) frame = cv2.flip(frame, 1) self.image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888) self.imageLabel.setPixmap(QPixmap.fromImage(self.image)) """ 下面是設定glassesButton的function """ """ 在tabWidget中 放很多個tab 代表各種眼鏡種類 每個tab會放一個scrollArea 每個scrollArea中放一個QWidget(稱buttons) buttons中放許多pushButton 每個pushButton都代表一個眼鏡 按下就讓畫面中的人戴上眼鏡 """ def setTabWidget(self, faceShape): # glassesShape[0]存絕配眼鏡 glassesShape[1]存可搭配的眼鏡 path = os.path.join(os.path.dirname(__file__), "datas", "recommendType", faceShape + ".txt") fin = open(path, 'r') # 第一次讀絕配眼鏡 第二次讀可搭配的眼鏡 for i in range(2): num = int(fin.readline()) for j in range(num): glassesShape = fin.readline().strip("\n") # 建立一個tabWidget tab = self.createScrollArea(glassesShape) self.tabWidget.addTab(tab, glassesShape) # 將絕配眼鏡種類和可搭配眼鏡種類以字體顏色做出區別 if i == 0: # 絕配為綠色 self.tabWidget.tabBar().setTabTextColor( j, QColor(0, 100, 0)) if i == 1: # 可搭配為黃色 self.tabWidget.tabBar().setTabTextColor( self.numOfTab + j, QColor(255, 165, 0)) self.numOfTab += num def createScrollArea(self, glassesType): scrollArea = QScrollArea() scrollArea.setWidget(self.setButtons(glassesType)) return scrollArea def setButtons(self, glassesType): buttons = QWidget() layout = QVBoxLayout() glassesFileAddr = "images/glasses/" + str(glassesType) path = os.path.join(os.path.dirname(__file__), glassesFileAddr) # 根據資料夾中眼鏡照片的數量來依序建立按鈕 for i in range(self.numOfGlasses(path)): glassesImgAddr = glassesFileAddr + "/" + str(i + 1) + ".png" path = os.path.join(os.path.dirname(__file__), glassesImgAddr) btn = QPushButton() btn.setIcon(QIcon(path)) btn.setIconSize(QtCore.QSize(128, 128)) btn.pressed.connect( lambda val=glassesImgAddr: self.putOnGlasses(val)) layout.addWidget(btn) buttons.setLayout(layout) return buttons def numOfGlasses(self, filePath): # fileInfo有三種資料 # fileInfo[0]為檔案位址 fileInfo[1]為子資料夾名稱 fileInfo[2]為資料夾內檔案名稱 fileInfo = next(os.walk(filePath)) return len(fileInfo[2]) """ 上面是設定glassesButton的function """ @QtCore.Slot() def takePicture(self): if not self.timer.isActive(): return self.timer.stop() _, frame = self.capture.read() frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) frame = cv2.flip(frame, 1) self.image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888) path = os.path.join(os.path.dirname(__file__), "images", "saved.jpg") self.image.save(path, "JPG") faceShape = faceShapeRecognizer.run() if (faceShape == "error1" or faceShape == "error2" or faceShape == "error3"): self.faceshapeOfUser.setText("請取消重拍 並再試一次") else: self.faceshapeOfUser.setText("你是" + faceShape + "臉") self.setTabWidget(faceShape) @QtCore.Slot() def cancelTakePicture(self): self.timer.start(30) # 刪除glassesButtons for i in range(self.numOfTab): self.tabWidget.removeTab(0) self.numOfTab = 0 self.faceshapeOfUser.setText("按下拍照來確認自己臉型") @QtCore.Slot() def revert(self): if self.timer.isActive(): return path = os.path.join(os.path.dirname(__file__), "images", "saved.jpg") self.imageLabel.setPixmap(QPixmap.fromImage(path)) @QtCore.Slot(str) def putOnGlasses(self, str): pictureCompound.run(str) path = os.path.join(os.path.dirname(__file__), "images", "result.jpg") self.image = QImage(path) self.imageLabel.setPixmap(QPixmap.fromImage(self.image))
class MainWindow(QMainWindow): def __init__(self): # load setting json file with open('setting.json') as f: self.app_setting = json.load(f) # Status of window super().__init__() self.title = 'Image Editor' self.left = 70 self.top = 70 self.width = 800 self.height = 700 # Status of view image self.org_qimg = None self.org_img_width = 0 self.org_img_height = 0 self.layer_pixmap = None self.layer_width = 0 self.layer_height = 0 self.layer_alpha = 50.0 # Prepare color bar data self.colormap_gain = self.app_setting["SoftwareSetting"]["process"][ "colormap"]["gain"] self.colormap_offset_x = self.app_setting["SoftwareSetting"][ "process"]["colormap"]["offset_x"] self.colormap_offset_green = self.app_setting["SoftwareSetting"][ "process"]["colormap"]["offset_green"] self.colormap_data = [ colormap.colorBarRGB(x * 0.001, self.colormap_offset_x, self.colormap_offset_green, self.colormap_gain) for x in range(1000) ] self.img_edit_mode = 'cursor' self.draw_color = QColor(255, 0, 0) self.draw_tool_size = 5 self.eraser_color = QColor(0, 0, 0, 0) # setup user interface components self.setup_ui() # Setup user interface components def setup_ui(self): # Set main window title self.setWindowTitle(self.title) # Set main wiodow initial position self.setGeometry(self.left, self.top, self.width, self.height) # Set up mainWindow's layout self.mainWidget = QWidget(self) # Note not to forget this code. self.main_layout = QVBoxLayout() # Set menu for main window self.main_menu = self.menuBar() self.file_menu = self.main_menu.addMenu('File') self.edit_menu = self.main_menu.addMenu('Edit') self.help_menu = self.main_menu.addMenu('Help') self.main_layout.addWidget(self.main_menu) # Set "Original Image Open" menu self.org_img_open_button = QAction( self.style().standardIcon(getattr(QStyle, 'SP_FileDialogStart')), 'Open Orginal Image', self) self.org_img_open_button.setShortcut('Ctrl+O') self.org_img_open_button.triggered.connect(self.open_org_img_dialog) self.file_menu.addAction(self.org_img_open_button) # Set "Save layer image" menu self.layer_img_save_button = QAction( self.style().standardIcon(getattr(QStyle, 'SP_FileDialogEnd')), 'Save Layer Image', self) self.layer_img_save_button.setShortcut('Ctrl+S') self.layer_img_save_button.triggered.connect(self.save_layer_image) self.file_menu.addAction(self.layer_img_save_button) # Set "Save compose image(original + layer image)" menu self.compose_img_save_button = QAction( self.style().standardIcon(getattr(QStyle, 'SP_FileDialogEnd')), 'Save Compose Image', self) self.compose_img_save_button.setShortcut('Ctrl+D') self.compose_img_save_button.triggered.connect(self.save_compose_image) self.file_menu.addAction(self.compose_img_save_button) # Set "exit software" menu self.exit_button = QAction( self.style().standardIcon(getattr(QStyle, 'SP_DialogCloseButton')), 'Exit', self) self.exit_button.setShortcut('Ctrl-Q') self.exit_button.setStatusTip('Exit software') self.exit_button.triggered.connect(self.close) self.file_menu.addAction(self.exit_button) self.upper_layout = QHBoxLayout() self.main_layout.addLayout(self.upper_layout) # Set image display area self.gview_default_size = 500 self.graphics_view = QGraphicsView() self.graphics_view.setFixedSize(self.gview_default_size, self.gview_default_size) self.graphics_view.setObjectName("imageDisplayArea") self.upper_layout.addWidget(self.graphics_view) # image display area's contents self.scene = GraphicsSceneForMainView(self.graphics_view, self) self.imgs_pixmap = [] self.imgs = [] self.img_status_layout = QVBoxLayout() self.upper_layout.addLayout(self.img_status_layout) # Set tranparency value of layer image self.transparency_title_label = QLabel('layer transparency value') self.img_status_layout.addWidget(self.transparency_title_label) transparency = round((1.0 - self.layer_alpha / 255.0) * 100) self.img_transparency_edit = QLineEdit(str(transparency)) self.img_transparency_sld = QSlider(Qt.Horizontal) self.img_transparency_sld.setFocusPolicy(Qt.NoFocus) self.img_transparency_sld.setRange(0, 100) self.img_transparency_sld.setValue(transparency) self.transparency_layout = QFormLayout() self.transparency_layout.addRow(self.img_transparency_sld, self.img_transparency_edit) self.img_status_layout.addLayout(self.transparency_layout) # Signal of transparency value changed self.img_transparency_sld.valueChanged.connect( self.transparency_change_sld) self.img_transparency_edit.textChanged.connect( self.transparency_change_edit) self.img_editor_layout = QVBoxLayout() self.img_status_layout.addLayout(self.img_editor_layout) # Set layer image editor tool self.img_editor_tool1_layout = QHBoxLayout() self.img_editor_layout.addLayout(self.img_editor_tool1_layout) self.tool_button_size = 64 # Set Mouse cursor self.mouse_cursor_button = QPushButton() self.mouse_cursor_button.setIcon(QIcon('icon/cursor.png')) self.mouse_cursor_button.setCheckable(True) self.mouse_cursor_button.setIconSize( QSize(self.tool_button_size, self.tool_button_size)) self.img_editor_tool1_layout.addWidget(self.mouse_cursor_button) # Set Pen self.pen_button = QPushButton() self.pen_button.setIcon(QIcon('icon/pen.png')) self.pen_button.setCheckable(True) self.pen_button.setIconSize( QSize(self.tool_button_size, self.tool_button_size)) self.img_editor_tool1_layout.addWidget(self.pen_button) # Set Eraser self.eraser_button = QPushButton() self.eraser_button.setIcon(QIcon('icon/eraser.png')) self.eraser_button.setCheckable(True) self.eraser_button.setIconSize( QSize(self.tool_button_size, self.tool_button_size)) self.img_editor_tool1_layout.addWidget(self.eraser_button) # Group button of mouse cursor, pen, eraser self.img_editor_tool1_group1 = QButtonGroup() self.img_editor_tool1_group1.addButton(self.mouse_cursor_button, 1) self.img_editor_tool1_group1.addButton(self.pen_button, 2) self.img_editor_tool1_group1.addButton(self.eraser_button, 3) # Set signal-slot of image editor button self.mouse_cursor_button.toggled.connect( self.mouse_cursor_button_toggled) self.pen_button.toggled.connect(self.pen_button_toggled) self.eraser_button.toggled.connect(self.eraser_button_toggled) # Set color bar self.color_bar_width = 64 self.color_bar_height = 256 self.color_bar_view = QGraphicsView() self.color_bar_view.setFixedSize(self.color_bar_width + 3, self.color_bar_height + 3) self.color_bar_scene = GraphicsSceneForTools() self.color_bar_img = QImage(self.color_bar_width, self.color_bar_height, QImage.Format_RGB888) for i in range(self.color_bar_height): # Set drawing pen for colormap ii = round(i * (1000 / 256)) color = QColor(self.colormap_data[ii][0], self.colormap_data[ii][1], self.colormap_data[ii][2]) pen = QPen(color, 1, Qt.SolidLine, \ Qt.SquareCap, Qt.RoundJoin) self.color_bar_scene.addLine(0, self.color_bar_height - i - 1, self.color_bar_width, self.color_bar_height - i - 1, pen=pen) for j in range(self.color_bar_width): self.color_bar_img.setPixelColor(j, self.color_bar_height - i - 1, color) self.color_bar_scene.set_img_content(self.color_bar_img) self.color_bar_view.setScene(self.color_bar_scene) # Connect signal to slot of color_bar_scene self.color_bar_scene.img_info.connect(self.set_selected_color) self.img_editor_tool1_layout.addWidget(self.color_bar_view) # Set thickness of Pen or Eraser self.draw_status_layout = QVBoxLayout() self.draw_thick_title_label = QLabel('thickness of pen or eraser') self.draw_status_layout.addWidget(self.draw_thick_title_label) self.draw_thick_edit = QLineEdit(str(self.draw_tool_size)) self.draw_thick_sld = QSlider(Qt.Horizontal) self.draw_thick_sld.setFocusPolicy(Qt.NoFocus) self.draw_thick_sld.setRange(1, 30) self.draw_thick_sld.setValue(self.draw_tool_size) self.draw_thick_layout = QFormLayout() self.draw_thick_layout.addRow(self.draw_thick_sld, self.draw_thick_edit) self.draw_status_layout.addLayout(self.draw_thick_layout) self.img_editor_layout.addLayout(self.draw_status_layout) # Signal of draw thickness value changed self.draw_thick_sld.valueChanged.connect(self.draw_thick_change_sld) self.draw_thick_edit.textChanged.connect(self.draw_thick_change_edit) # Set view area of selected color self.select_color_view_size = 64 self.select_color_view = QGraphicsView() self.select_color_view.setFixedSize(self.select_color_view_size + 3, self.select_color_view_size + 3) self.select_color_scene = QGraphicsScene() brush = QBrush(self.draw_color) self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \ brush=brush) self.select_color_view.setScene(self.select_color_scene) self.select_color_title_label = QLabel('Selected color') self.selected_color_layout = QFormLayout() self.selected_color_layout.addRow(self.select_color_title_label, self.select_color_view) self.img_editor_layout.addLayout(self.selected_color_layout) # Set save button self.save_button_layout = QHBoxLayout() self.img_status_layout.addLayout(self.save_button_layout) self.layer_save_button = QPushButton('Save layer image') self.layer_save_button.setIcon(QIcon('icon/layer_save.png')) self.layer_save_button.setIconSize( QSize(self.tool_button_size, self.tool_button_size)) self.compose_save_button = QPushButton( 'Save composed original and layer image') self.compose_save_button.setIcon(QIcon('icon/compose_save.png')) self.compose_save_button.setIconSize( QSize(self.tool_button_size, self.tool_button_size)) self.save_button_layout.addWidget(self.layer_save_button) self.save_button_layout.addWidget(self.compose_save_button) self.layer_save_button.clicked.connect(self.save_layer_image) self.compose_save_button.clicked.connect(self.save_compose_image) # Set display area of selected file path self.org_img_path_title_label = QLabel('original image file: ') self.org_img_path_label = QLabel('') self.file_path_layout = QFormLayout() self.file_path_layout.addRow(self.org_img_path_title_label, self.org_img_path_label) self.bottom_layout = QVBoxLayout() self.bottom_layout.addLayout(self.file_path_layout) self.main_layout.addLayout(self.bottom_layout) self.mainWidget.setLayout(self.main_layout) self.setCentralWidget(self.mainWidget) # Original image select Function def open_org_img_dialog(self): options = QFileDialog.Options() org_img_default_path = self.app_setting["SoftwareSetting"][ "file_path"]["org_img_dir"] self.org_img_file_path, selected_filter = QFileDialog.getOpenFileName(self, 'Select original image', org_img_default_path, \ 'Image files(*.jpg *jpeg *.png)', options=options) org_img_dir_path, org_img_file = os.path.split(self.org_img_file_path) org_img_bare_name, org_img_ext = os.path.splitext(org_img_file) self.org_img_path_label.setText(self.org_img_file_path) self.set_image_on_viewer() def set_image_on_viewer(self): # Delete existing image item if len(self.imgs_pixmap) != 0: for item in self.imgs_pixmap: self.scene.removeItem(item) self.scene.clear_contents() self.imgs_pixmap.clear() self.imgs.clear() # load original image self.org_qimg = QImage(self.org_img_file_path) self.org_pixmap = QPixmap.fromImage(self.org_qimg) org_img_size = self.org_qimg.size() self.org_img_width = org_img_size.width() self.org_img_height = org_img_size.height() # Set layer image self.layer_qimg = QImage(self.org_img_width, self.org_img_height, QImage.Format_RGBA8888) self.layer_qimg.fill(QColor(0, 0, 0, self.layer_alpha)) self.layer_pixmap = QPixmap.fromImage(self.layer_qimg) self.imgs.append(self.org_qimg) self.imgs.append(self.layer_qimg) # Set image to scene self.imgs_pixmap.append(QGraphicsPixmapItem(self.org_pixmap)) self.scene.addItem(self.imgs_pixmap[-1]) self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap)) self.scene.addItem(self.imgs_pixmap[-1]) self.scene.set_img_contents(self.imgs) # Set scene to graphics view self.graphics_view.setScene(self.scene) self.graphics_view.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.show() # Slot function of transparency slider changed def transparency_change_sld(self, value): self.img_transparency_edit.setText(str(value)) self.layer_alpha = int(255 * (1.0 - (value / 100))) # Change layer image's transparency(alpha value) for y in range(self.org_img_height): for x in range(self.org_img_width): self.layer_qimg.setPixelColor( QPoint(x, y), QColor(0, 0, 0, self.layer_alpha)) self.layer_pixmap = QPixmap.fromImage(self.layer_qimg) # remove previous layer image self.scene.removeItem(self.imgs_pixmap[-1]) self.imgs_pixmap.pop(-1) # add new layer image to scene self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap)) self.scene.addItem(self.imgs_pixmap[-1]) self.show() # Slot function of transparency text edit changed def transparency_change_edit(self, value): if int(value) < 0 or int(value) > 100: return self.img_transparency_sld.setValue(int(value)) self.layer_alpha = int(255 * (1.0 - (int(value) / 100.0))) # Change layer image's transparency(alpha value) for y in range(self.org_img_height): for x in range(self.org_img_width): self.layer_qimg.setPixelColor( QPoint(x, y), QColor(0, 0, 0, self.layer_alpha)) self.layer_pixmap = QPixmap.fromImage(self.layer_qimg) # remove previous layer image self.scene.removeItem(self.imgs_pixmap[-1]) self.imgs_pixmap.pop(-1) # add new layer image to scene self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap)) self.scene.addItem(self.imgs_pixmap[-1]) self.show() # slot(receiver of signal) of mouse_cursor_button toggled def mouse_cursor_button_toggled(self, checked): if checked: self.img_edit_mode = 'cursor' self.scene.set_mode(self.img_edit_mode) self.color_bar_scene.set_mode(self.img_edit_mode) # slot(receiver of signal) of pen_button toggled def pen_button_toggled(self, checked): if checked: self.img_edit_mode = 'pen' self.scene.set_mode(self.img_edit_mode) self.color_bar_scene.set_mode(self.img_edit_mode) # slot(receiver of signal) of eraser_button toggled def eraser_button_toggled(self, checked): if checked: self.img_edit_mode = 'eraser' self.scene.set_mode(self.img_edit_mode) self.color_bar_scene.set_mode(self.img_edit_mode) self.draw_color = self.eraser_color self.select_color_scene.removeItem(self.select_color_rect) brush = QBrush(self.draw_color) self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \ brush=brush) self.select_color_view.setScene(self.select_color_scene) # Slot of color bar clicked for selection color def set_selected_color(self, color): # Delete existng image item self.select_color_scene.removeItem(self.select_color_rect) self.draw_color = color brush = QBrush(self.draw_color) self.select_color_rect = self.select_color_scene.addRect(QRect(0, 0, self.select_color_view_size, self.select_color_view_size), \ brush=brush) self.select_color_view.setScene(self.select_color_scene) # Slot function of draw thicikeness slider changed def draw_thick_change_sld(self, value): self.draw_thickness_edit.setText(str(value)) self.draw_tool_size = value # Slot function of draw thicikeness text editor changed def draw_thick_change_edit(self, value): if int(value) < 1 or int(value) > 30: return self.draw_thickness_sld.setValue(int(value)) def make_layer_image(self): for i, line in enumerate(self.scene.lines): pen = self.scene.pens[i] pen_size = int(pen.width()) pen_color = pen.color() # start pixel of line x1 = int(line.x1()) y1 = int(line.y1()) # end pixel of line x2 = int(line.x2()) y2 = int(line.y2()) dx = int(line.dx()) dy = int(line.dy()) # When only 1pixl line if dx <= 1 and dy <= 1: draw_pix_x1_s = max(x1 - int(pen_size / 2), 0) draw_pix_x1_e = min(x1 + int(pen_size / 2), self.org_img_width - 1) draw_pix_y1_s = max(y1 - int(pen_size / 2), 0) draw_pix_y1_e = min(y1 + int(pen_size / 2), self.org_img_height - 1) # for Pen's size for y in range(draw_pix_y1_s, draw_pix_y1_e): for x in range(draw_pix_x1_s, draw_pix_x1_e): self.layer_qimg.setPixelColor(x, y, pen_color) draw_pix_x2_s = max(x2 - int(pen_size / 2), 0) draw_pix_x2_e = min(x2 + int(pen_size / 2), self.org_img_width - 1) draw_pix_y2_s = max(y2 - int(pen_size / 2), 0) draw_pix_y2_e = min(y2 + int(pen_size / 2), self.org_img_height - 1) # for Pen's size for y in range(draw_pix_y2_s, draw_pix_y2_e): for x in range(draw_pix_x2_s, draw_pix_x2_e): self.layer_qimg.setPixelColor(x, y, pen_color) else: # For avoid devide by 0 if dx == 0: for y in range(y1, y2 + 1): draw_pix_y_s = y - int(pen_size / 2) draw_pix_y_e = y + int(pen_size / 2) # for Pen's size for yy in range(draw_pix_y_s, draw_pix_y_e): self.layer_qimg.setPixelColor(x1, yy, pen_color) else: grad = dy / dx # Choose coordinates with small slope not to skip pixels if grad >= 1.0: for x in range(dx): y = y1 + int(grad * x + 0.5) draw_pix_x_s = max(x1 + x - int(pen_size / 2), 0) draw_pix_x_e = min(x1 + x + int(pen_size / 2), self.org_img_width - 1) draw_pix_y_s = max(y - int(pen_size / 2), 0) draw_pix_y_e = min(y + int(pen_size / 2), self.org_img_height - 1) # for Pen's size for yy in range(draw_pix_y_s, draw_pix_y_e + 1): for xx in range(draw_pix_x_s, draw_pix_x_e + 1): self.layer_qimg.setPixelColor( xx, yy, pen_color) else: for y in range(dy): x = x1 + int(1 / grad * y + 0.5) draw_pix_y_s = max(y1 + y - int(pen_size / 2), 0) draw_pix_y_e = min(y1 + y + int(pen_size / 2), self.org_img_height - 1) draw_pix_x_s = max(x - int(pen_size / 2), 0) draw_pix_x_e = min(x + int(pen_size / 2), self.org_img_width - 1) # for Pen's size for yy in range(draw_pix_y_s, draw_pix_y_e + 1): for xx in range(draw_pix_x_s, draw_pix_x_e + 1): self.layer_qimg.setPixelColor( xx, yy, pen_color) # Slot function of save layer image button clicked def save_layer_image(self): self.make_layer_image() layer_img_default_path = self.app_setting["SoftwareSetting"][ "file_path"]["layer_img_dir"] options = QFileDialog.Options() file_name, selected_filete = QFileDialog.getSaveFileName(self, 'Save layer image', layer_img_default_path, \ 'image files(*.png, *jpg)', options=options) #print('layer image save name:{file}'.format(file=file_name)) self.layer_qimg.save(file_name) ret = QMessageBox(self, 'Success', 'layer image is saved successfully', QMessageBox.Ok) # Make composed orignal and layered image def make_compose_image(self): self.make_layer_image() self.compose_qimg = QImage(self.org_img_width, self.org_img_height, QImage.Format_RGBA8888) painter = QPainter(self.compose_qimg) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) painter.drawImage(0, 0, self.org_qimg) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) painter.drawImage(0, 0, self.layer_qimg) painter.end() # Slot function of save composer original and layer image button clicked def save_compose_image(self): self.make_compose_image() compose_img_default_path = self.app_setting["SoftwareSetting"][ "file_path"]["compose_img_dir"] options = QFileDialog.Options() file_name, selected_fileter = QFileDialog.getSaveFileName(self, 'Save composed image', compose_img_default_path, \ 'image files(*.png, *jpg)', options=options) #print('compose image save name:{file}'.format(file=file_name)) self.compose_qimg.save(file_name) ret = QMessageBox(self, 'Success', 'compose image is saved successfully', QMessageBox.Ok)
def saveSceneToFile(self, filename, imageformat, transparent, rastsize): ''' Save the current scene to the named file. If imageformat is empty or None, the format is guessed from the filename extension. If transparent is False, the entire scene is initialized to the last clearing color. If given, rastsize is the pixels size of the saved image. If rastsize is not given, the saved image will be saved at the current scaled image size. ''' # This could be called when there is no image present. # If this is the case, ignore the call. if (self.__sceneimage == None): return if not imageformat: # Guess the image format from the filename extension # This is only done to silently change gif to png fileext = (os.path.splitext(filename)[1]).lower() if fileext == '.gif': myformat = 'gif' else: # let QImage figure out the format myformat = None else: myformat = imageformat.lower() if myformat == 'gif': # Silently convert gif filename and format to png myformat = 'png' myfilename = os.path.splitext(filename)[0] + ".png" else: myfilename = filename # set the cursor and status message to indicate a save is happending QApplication.setOverrideCursor(Qt.WaitCursor) self.statusBar().showMessage(self.tr("Saving image")) try: if rastsize: imagewidth = int(rastsize.width() + 0.5) imageheight = int(rastsize.height() + 0.5) else: imagewidth = int(self.__scenewidth * self.__scalefactor + 0.5) imageheight = int(self.__sceneheight * self.__scalefactor + 0.5) myimage = QImage(QSize(imagewidth, imageheight), QImage.Format_ARGB32_Premultiplied) # Initialize the image if not transparent: # Clear the image with self.__lastclearcolor fillint = self.__helper.computeARGB32PreMultInt( self.__lastclearcolor) else: fillint = 0 myimage.fill(fillint) # draw the scaled scene to this QImage mypainter = QPainter(myimage) trgrect = QRectF(0.0, 0.0, float(imagewidth), float(imageheight)) srcrect = QRectF(0.0, 0.0, float(self.__scenewidth), float(self.__sceneheight)) mypainter.drawImage(trgrect, self.__sceneimage, srcrect, Qt.AutoColor) mypainter.end() # save the image to file if not myimage.save(myfilename, myformat): raise ValueError("Unable to save the plot as " + myfilename) finally: self.statusBar().clearMessage() QApplication.restoreOverrideCursor()
class Map(QQuickPaintedItem): def __init__(self, parent = None): super(Map, self).__init__(parent) self.viewport = None self.setAcceptedMouseButtons(Qt.AllButtons) self.generate() clicked = Signal(QPoint) @Slot() def generate(self): # QImage does not work with bits, only with bytes self.image = QImage(300, 300, QImage.Format_Grayscale8) self.oldImage = None self.generateMap() self._percentage = 0 self._pressClick = QPoint() def pixel(self, x: int, y: int, image = None) -> bool: if not image: image = self.image # This solves: # QImage::pixelIndex: Not applicable for 8-bpp images (no palette) return image.bits()[int(x) + int(y) * image.bytesPerLine()] & 0xff def setPixel(self, x: int, y: int, value: int, image = None): if not image: image = self.image # This solves: # QImage::pixelIndex: Not applicable for 8-bpp images (no palette) image.bits()[int(x) + int(y) * image.bytesPerLine()] = value def createRandomMap(self): for i in range(self.image.byteCount()): if random.random() < 0.35: self.image.bits()[i] = 255 else: self.image.bits()[i] = 0 def countNeighbors(self, x: int, y: int, image = None, n = 1) -> int: if not image: image = self.image count = 0 for i in range(-n , n + 1): for u in range(-n , n + 1): if not i and not u: continue #TODO: pixel function is poor # need to use bits() if x + i < 0 or y + u < 0 or \ x + i >= image.width() or y + u >= image.height(): count += 1 continue if not self.pixel(x + i, y + u, image): count += 1 return count @Slot(int) def doStep(self, n = 1): if self.image.format() != QImage.Format_Grayscale8: print("Wrong file format, generate map again.") return deathLimit = 14 self._percentage = 0 for _ in range(n): _image = self.image.copy() for x in range(self.image.width()): self._percentage += 1.0/(self.image.width()*n) if x%10 == 0: # Update percentage self.percentageChanged.emit() # processEvent is necessary QEventLoop().processEvents() # Update map self.update() for y in range(self.image.height()): if self.countNeighbors(x, y, _image, 2) > deathLimit or \ x == 0 or y == 0 or x == _image.width() - 1 or y == _image.height() - 1: self.setPixel(x, y, 0) else: self.setPixel(x, y, 255) # Update percentage self.update() self.oldImage = self.image.copy() self.percentageChanged.emit() QEventLoop().processEvents() def generateMap(self): self.createRandomMap() self.update() self.oldImage = self.image.copy() def paint(self, painter): painter.drawImage(QRect(0, 0, self.width(), self.height()), self.image) self.viewport = painter.viewport() def keyPressEvent(self, event): if event.key() == Qt.Key_Space: print('Update..') start = time.time() self.doStep() print('Took: %.2fs' % (time.time() - start)) event.accept() def mousePressEvent(self, event): a, b = event.pos().x()*self.image.width()/self.width(), event.pos().y()*self.image.height()/self.height() self.clicked.emit(QPoint(a, b)) def mouseMoveEvent(self, event): a, b = event.pos().x()*self.image.width()/self.width(), event.pos().y()*self.image.height()/self.height() self.clicked.emit(QPoint(a, b)) def percentage(self): return self._percentage percentageChanged = Signal() percentage = Property(float, percentage, notify=percentageChanged) @Slot() def addVehicle(self): self.image = self.image.convertToFormat(QImage.Format_RGBA8888) painter = QPainter(self.image) painter.drawImage(QRect(50, 50, 13, 15), QImage("imgs/turtle.png")) painter.end() self.update() @Slot(str) def saveMap(self, path: str): # Check image encoder if(self.image.format() != QImage.Format_Grayscale8): print('Wrong map pixel format, create map without vehicle added.') return ok = self.image.save(path) if(not ok): print('It was not possible to save Map in:', path) @Slot(str) def loadMap(self, path: str): # Check image encoder image = QImage(path) if(image.format() != QImage.Format_Grayscale8): print('Wrong map pixel format, map should be Grayscale8.') return self.image = image self.oldImage = self.image.copy() self.update()