Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
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
Exemple #4
0
 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:]
Exemple #5
0
 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())
Exemple #6
0
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')
Exemple #7
0
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)
Exemple #8
0
    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))
Exemple #9
0
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
Exemple #10
0
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)
Exemple #11
0
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))
Exemple #12
0
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()
Exemple #14
0
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()