示例#1
0
    def convert(self) -> Texture2DDescription:
        self.validate()

        from PySide6.QtGui import QImage
        img = QImage(self.filePath)
        n = _cChannels[self.channels]
        if n == 4:
            img = img.convertToFormat(QImage.Format_RGBA8888)
        else:
            img = img.convertToFormat(QImage.Format_RGB888)

        # noinspection PyTypeChecker
        bits: memoryview = img.constBits()
        # noinspection PyTypeChecker
        byts: bytes = bits.tobytes()
        w, h = img.width(), img.height()
        if n == 1:
            assert len(byts) == w * h * 3
            byts = byts[::3]
            assert len(byts) == w * h
        elif n == 2:
            assert len(byts) == w * h * 3
            byts = b''.join(byts[i:i + 2] for i in range(len(byts) // 3))
            assert len(byts) == w * h * 2

        desc = Texture2DDescription(w, h, byts, self.channels, self.dataFormat,
                                    self.tilingX, self.mipMaps, self.linearFiltering)
        desc.tilingY = self.tilingY
        desc._label = self._label
        return desc
示例#2
0
def display_diff(actual_image: QImage, diff_image: QImage,
                 expected_image: QImage, diff_count: int):
    # Display image when in live turtle mode.
    display_image = getattr(turtle.Turtle, 'display_image', None)
    if display_image is None:
        return
    t = turtle.Turtle()
    # noinspection PyUnresolvedReferences
    screen = t.screen  # type: ignore
    w = screen.cv.cget('width')
    h = screen.cv.cget('height')
    ox, oy = w / 2, h / 2
    text_space = (h - actual_image.height() - diff_image.height() -
                  expected_image.height())
    text_height = max(20, text_space // 3)
    font = ('Arial', text_height // 2, 'Normal')
    t.penup()
    t.goto(-ox, oy)
    t.right(90)
    t.forward(text_height)
    t.write(f'Actual', font=font)
    display_image(ox + t.xcor(),
                  oy - t.ycor(),
                  image=encode_image(actual_image))
    t.forward(actual_image.height())
    t.forward(text_height)
    t.write(f'Diff ({diff_count} pixels)', font=font)
    display_image(ox + t.xcor(), oy - t.ycor(), image=encode_image(diff_image))
    t.forward(diff_image.height())
    t.forward(text_height)
    t.write('Expected', font=font)
    display_image(ox + t.xcor(),
                  oy - t.ycor(),
                  image=encode_image(expected_image))
    t.forward(expected_image.height())
示例#3
0
 def export_arr(self, frame_index: int):
     self.scene.update_frame(frame_index)
     img = QImage(self.video_data.width, self.video_data.height,
                  QImage.Format_ARGB32)
     painter = QPainter()
     painter.begin(img)
     self.scene.render(painter)
     painter.end()
     shape = (img.height(), img.bytesPerLine() * 8 // img.depth(), 4)
     ptr = img.bits()
     arr = np.array(ptr, dtype=np.uint8).reshape(shape)
     arr = arr[..., :3]
     return arr
示例#4
0
class MainWindow(QMainWindow):
    bytes_key = bytes((0b11100010, 0b10011101, 0b10100100))

    def __init__(self):
        super(MainWindow, self).__init__(None)
        self.ui = UiMainWindow()
        self.data = Coder()
        self.ui.setup_ui(self)

        self.ui.text_edit.textChanged.connect(self.message_changed)
        self.ui.push_button.clicked.connect(self.read_image)
        self.ui.push_button_2.clicked.connect(self.write_image)
        self.ui.push_button_4.clicked.connect(self.encode_text)
        self.ui.push_button_3.clicked.connect(self.decode_text)
        self.image = None
        self.ui.label.setWordWrap(True)
        self.reset_state()

    def clear_image(self):
        if not self.image:
            return

        del self.image
        self.image = None

    def reset_state(self):
        self.clear_image()
        self.update_activity_state()

    def update_activity_state(self):
        self.ui.text_edit.setEnabled(self.image is not None)
        self.ui.push_button_2.setEnabled(self.image is not None)
        self.ui.push_button_3.setEnabled(self.image is not None)
        self.ui.push_button_4.setEnabled(self.image is not None)

    def get_input(self):
        return self.ui.text_edit.toPlainText()

    @Slot()
    def read_image(self):
        filepath, _ = QFileDialog.getOpenFileName(
            self, "Открыть картинку", "", "Допустимые форматы (*.png)")

        if not filepath:
            return

        self.reset_state()

        if not QFile.exists(filepath):
            self.set_output_message(
                "Изображение {} не найдено.".format(filepath))
            return

        self.image = QImage()
        if not self.image.load(filepath):
            self.set_output_message(
                "Изображение {} не загружено.".format(filepath))
            self.clear_image()
            return

        self.image.convertTo(QImage.Format_ARGB32)

        self.data.max_power = (self.image.width() * self.image.height() *
                               3) // 8 - len(MainWindow.bytes_key) - 4

        self.set_output_message("Изображение успешно загружено")
        self.update_activity_state()

    @Slot()
    def write_image(self):
        if self.image is None:
            self.set_output_message("Ошибка загрузки")
            return

        filepath, _ = QFileDialog.getSaveFileName(
            self, "Сохранить картинку", "", "Допустимые форматы (*.png)")

        if self.image.save(filepath, "PNG"):
            self.set_output_message(
                "Изображение сохранено в {}".format(filepath))
            return

        self.set_output_message("Ошибка сохранения")

    @Slot()
    def encode_text(self):
        if self.image is None:
            self.set_output_message("Ошибка загрузки.")
            return

        array = QByteArray()
        array.push_back(self.get_input().encode())

        self.data.curr_power = len(array)

        if self.data.overflow():
            self.set_output_message(
                "Сильно большой текст для кодирования в эту картинку.")
            return

        for i in range(4):
            array.push_front(
                bytes(((self.data.curr_power >> in_bits(i)) & 0xff, )))

        for i in range(len(MainWindow.bytes_key) - 1, -1, -1):
            array.push_front(bytes((MainWindow.bytes_key[i], )))

        bytes_write(self.image, array, 0)

        self.set_output_message("Сообщение закодировано!")

    @Slot()
    def decode_text(self):
        if self.image is None:
            self.set_output_message("Ошибка загрузки!")
            return

        header = len(MainWindow.bytes_key) + 4

        array = bytes_read(self.image, 0, header)

        for i in range(0, len(MainWindow.bytes_key)):
            if bytes((MainWindow.bytes_key[i], )) != array[i]:
                self.set_output_message("Сообщение отсутствует!")
                return

        size = 0

        for i in range(len(MainWindow.bytes_key),
                       len(MainWindow.bytes_key) + 4):
            size = (size << 8) + int.from_bytes(array[i], byteorder="big")

        if size > self.data.max_power:
            self.set_output_message(
                "Ошибка декодирования! Размер заголовка превышает размер сообщения."
            )
            return

        array.clear()
        array = bytes_read(self.image, header, size)

        text = bytes(array).decode("utf-8")

        self.ui.text_edit.setPlainText(text)
        self.set_output_message(
            "Присутствует сообщение длиной {} байт.".format(size))

    @Slot()
    def message_changed(self):
        array = QByteArray()
        array.push_back(self.get_input().encode())
        self.data.curr_power = len(array)

        if self.data.less():
            argument = self.data.diff()
            self.set_output_message(
                "Ещё можно ввести: {} байт.".format(argument))
            return

        if self.data.max_():
            self.set_output_message("Размер сообщения достиг максимума.")
            return

        argument = self.data.rdiff()
        self.set_output_message(
            "Размер сообщения превышен на: {} байт.".format(argument))

    def set_output_message(self, text):
        self.ui.label.setText(text)
示例#5
0
文件: Image.py 项目: jono-m/uChip
 def InitializeSize(self):
     image = QImage(str(self.path.absolute()))
     self.size.setWidth(image.width())
     self.size.setHeight(image.height())
示例#6
0
class ImageView(MouseEventMixin, QGraphicsView):
    def __init__(self, dirname, parent=None):
        super(ImageView, self).__init__()
        super(MouseEventMixin, self).__init__(parent)
        self.__dirname = dirname
        self.__image = None
        self.__image_list = []
        self.__timer = QTimer(self)
        self.init_ui()

    def init_ui(self):
        self.setCacheMode(QGraphicsView.CacheBackground)
        self.setRenderHints(QPainter.Antialiasing
                            | QPainter.SmoothPixmapTransform
                            | QPainter.TextAntialiasing)

        self.__timer.setInterval(IMAGE_INTERVAL)
        self.__timer.timeout.connect(self.on_timeout)

    def init_image_list(self):
        self.__image_list = [
            str(x) for x in Path(self.__dirname).iterdir() if x.is_file()
        ]

    def start_view(self):
        self.init_image_list()
        self.random_set_image()
        self.__timer.start()

    def set_image(self, filename):
        self.setUpdatesEnabled(False)
        self.__image = QImage(filename)
        self.repaint()
        self.setUpdatesEnabled(True)

    def random_set_image(self):
        if not self.__image_list:
            return
        image = random.choice(self.__image_list)
        self.__image_list.remove(image)
        self.set_image(path.join(self.__dirname, image))

    def on_timeout(self):
        if not self.__image_list:
            self.init_image_list()
        self.random_set_image()

    def paintEvent(self, event):
        super(MouseEventMixin, self).paintEvent(event)

        if not self.__image:
            return

        if self.__image.height() == 0 or self.height(
        ) == 0 or self.__image.width() == 0:
            return

        image_aspect_ratio = self.__image.width() / self.__image.height()
        view_aspect_ratio = self.width() / self.height()
        if view_aspect_ratio <= image_aspect_ratio:
            image_height = self.width() / image_aspect_ratio
            rect = QRectF(0, (self.height() - image_height) / 2, self.width(),
                          image_height)
        else:
            image_widh = self.height() * image_aspect_ratio
            rect = QRectF((self.width() - image_widh) / 2, 0, image_widh,
                          self.height())

        painter = QPainter(self.viewport())
        painter.drawImage(rect, self.__image)
        painter.end()
class PreviewWindow(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mode = Mode.NoMode
        self.image = QImage()
        self.zoomed_image = QImage()
        self.svgRenderer = QSvgRenderer(self)
        self.zoom_scale = ZOOM_ORIGINAL_SCALE

    def mode(self):
        return self.mode

    def set_mode(self, mode):
        self.mode = mode

    def load(self, data):
        if self.mode == Mode.PngMode:
            self.image.loadFromData(data)
            self.setMinimumSize(self.image.rect().size())
        elif self.mode == Mode.SvgMode:
            self.svgRenderer.load(data)

        self.zoom_image()
        self.update()

    # Public slots
    def zoom_original(self):
        self.set_zoom_scale(ZOOM_ORIGINAL_SCALE)

    def zoom_in(self):
        # new_scale = self.zoom_scale + \
        #             ZOOM_BIG_INCREMENT if self.zoom_scale >= ZOOM_ORIGINAL_SCALE else ZOOM_SMALL_INCREMENT
        new_scale = self.zoom_scale + ZOOM_SMALL_INCREMENT
        if new_scale > MAX_ZOOM_SCALE:
            new_scale = MAX_ZOOM_SCALE
        self.set_zoom_scale(new_scale)

    def zoom_out(self):
        # new_scale = self.zoom_scale - \
        #             ZOOM_SMALL_INCREMENT if self.zoom_scale <= ZOOM_ORIGINAL_SCALE else ZOOM_BIG_INCREMENT
        new_scale = self.zoom_scale - ZOOM_SMALL_INCREMENT
        if new_scale < MIN_ZOOM_SCALE:
            new_scale = MIN_ZOOM_SCALE
        self.set_zoom_scale(new_scale)

    # Private methods

    def paintEvent(self, event):
        painter = QPainter(self)
        output_size = QSize()

        if self.mode == Mode.PngMode:
            output_size = self.zoomed_image.size()
            output_rect = QRect(QPoint(), output_size)
            output_rect.translate(self.rect().center() - output_rect.center())
            painter.drawImage(output_rect.topLeft(), self.zoomed_image)

        elif self.mode == Mode.SvgMode:
            output_size = self.svgRenderer.defaultSize()
            if self.zoom_scale != ZOOM_ORIGINAL_SCALE:
                zoom = float(self.zoom_scale) / ZOOM_ORIGINAL_SCALE
                output_size.scale(output_size.width() * zoom,
                                  output_size.height() * zoom,
                                  Qt.IgnoreAspectRatio)

            output_rect = QRect(QPoint(), output_size)
            output_rect.translate(self.rect().center() - output_rect.center())
            self.svgRenderer.render(painter, output_rect)

        self.setMinimumSize(output_size)

    def zoom_image(self):
        if self.mode == Mode.PngMode:
            if self.zoom_scale == ZOOM_ORIGINAL_SCALE:
                self.zoomed_image = self.image
            else:
                zoom = float(self.zoom_scale) / ZOOM_ORIGINAL_SCALE
                self.zoomed_image = self.image.scaled(
                    self.image.width() * zoom,
                    self.image.height() * zoom, Qt.IgnoreAspectRatio,
                    Qt.SmoothTransformation)

    def set_zoom_scale(self, new_scale):
        if self.zoom_scale != new_scale:
            self.zoom_scale = new_scale
            self.zoom_image()
            self.update()
示例#8
0
文件: hexview.py 项目: sthagen/amoco
class HexView(QAbstractScrollArea):
    """
    HexView is a QAbstractScrollArea (not a QScrollArea in order to
    handle large list of hexlines to display. A QScrollArea would require
    that the viewport Widget associated to it be fully defined to handle
    the scrolling automatically. Here we really want to render the viewport
    dynamically based on scrolling events, not the opposite.)
    """
    clicked = Signal((int, int, QColor))

    def __init__(self, parent=None, dataio=None):
        super().__init__(parent)
        # enforce monospaced font:
        f = QFont("Monospace")
        f.setPointSize(8)
        self.setFont(f)
        self.setFocusPolicy(Qt.StrongFocus)
        self.setMouseTracking(True)
        self.palette = cycle(colors.palette_trbg.values())
        self.lastcolor = None
        # set default vertical scrolling steps:
        self.vb = self.verticalScrollBar()
        # addresses to be highlighted:
        self.highlight = {}
        self.selected = None
        # setup internal widgets:
        self.model = None
        self.statusbar = parent.statusBar() if parent else None
        if dataio:
            self.setData(dataio)

    @property
    def select_color(self):
        """
        get next color from (cycle) palette
        """
        self.lastcolor = next(self.palette)
        return self.lastcolor

    def setData(self, dataio):
        """
        Define the data model associated with the HexView and initialise
        the vertical bar values.
        """
        if self.model:
            self.model.deleteLater()
        # data should have DataIO API
        # the model is used as the interface with the data bytes
        self.model = models.DataIOModel(parent=self, data=dataio)
        # the view needs updating whenever the model emits a
        # "UPDATED" signal:
        self.model.UPDATED.connect(self.update)
        # since we are an "abstract" widget we need to compute the
        # vertical bar minimum/maximum values.
        self.vb.setMinimum(0)
        nb, r = divmod(self.model.data.size(), self.model.linesize)
        if r > 0: nb += 1
        self.vb.setMaximum(nb)
        # set line definition (sizes):
        self.line = HexLine(self.fontMetrics(), self.model.linesize)
        # prepare grayscale image of the full model data:
        self.qimg = QImage(self.model.full, self.model.linesize, nb,
                           QImage.Format_Grayscale8)
        self.update()

    def update(self):
        "trigger an update of the viewport widget (ie a paintEvent)"
        # this will trigger update (paint) on the children as well:
        self.viewport().update()

    def paintEvent(self, e):
        "(re)draw everything inside the rectangle associated with event e"
        if self.model is not None:
            # get the painting area:
            w = QPainter(self.viewport())
            f = self.font()
            w.setFont(f)
            # get rectangle that needs paint:
            r = e.rect()
            # get line indices for this rectangle:
            line0 = self.vb.value()
            h = self.line.height
            first = line0 + r.top() // h
            last = line0 + r.bottom() // h
            count = last - first
            # update drawing:
            self.paintlines(w, first, count, line0)
            self.paintframes(w)
            self.paintmap(w)

    def keyPressEvent(self, e):
        self.statusbar.showMessage("key: %d ('%s') [%08x]" %
                                   (e.key(), e.text(), e.modifiers()))
        if self.model is not None:
            if e.key() == int(Qt.Key_Escape):
                self.highlight = {}
            self.update()
        super().keyPressEvent(e)

    def addrToLine(self, addr):
        N = self.model.linesize
        l, off = divmod(addr, N)
        return l

    def xyToAddr(self, x, y):
        if x < self.line.x_map:
            h = self.line.height
            l = y // h
            # get base address
            a = self.model.linesize * (self.model.cur + l)
            # add byte index [0,16[
            return (a + self.line.index(x))
        h = self.viewport().height()
        a = int((y / h) * (self.qimg.height() * self.qimg.width()))
        a = (a // self.model.linesize) * self.model.linesize
        if a != 0 and self.selected and a != (self.selected[0]):
            return a - 1
        else:
            return a

    def colorize(self, a, nb, color):
        N = self.model.linesize
        base, o = divmod(a, N)
        a = base * N
        c = color
        while nb > 0:
            n = min(N - o, nb)
            if a not in self.highlight:
                self.highlight[a] = [None] * N
            for i in range(o, o + n):
                self.highlight[a][i] = c
            nb -= n
            a += N
            o = 0

    def adjust_selected(self, e):
        x, y = e.x(), e.y()
        a = self.xyToAddr(e.x(), e.y())
        if self.selected:
            aa, nb_, c = self.selected
            if a != aa:
                a, nb = (aa, a - aa) if aa < a else (a, aa - a)
                self.selected = (a, nb + 1, c)
            else:
                nb = 1
            self.colorize(a, nb_, None)
        else:
            if x < self.line.x_end:
                nb = 1
            elif x < self.line.x_map:
                nb = self.model.linesize
                a = a - (nb - 1)
            else:
                nb = self.model.linesize
            self.selected = (a, nb, self.select_color)
        msg = "selection: [addr=%08x, size=%d]" % (a, nb)
        self.statusbar.showMessage(msg)

    def mousePressEvent(self, e):
        self.adjust_selected(e)
        self.colorize(*self.selected)
        self.update()

    def mouseMoveEvent(self, e):
        if self.selected:
            self.adjust_selected(e)
            self.colorize(*self.selected)
            self.update()

    def mouseReleaseEvent(self, e):
        if self.selected:
            self.adjust_selected(e)
            self.colorize(*self.selected)
            self.update()
            self.clicked.emit(*self.selected)
            self.selected = None

    def wheelEvent(self, e):
        delta = 1 if e.angleDelta().y() < 0 else -1
        v = self.vb.value() + delta
        self.vb.setValue(v)
        msg = "wheel: delta=%d, v=%d" % (delta, v)
        self.statusbar.showMessage(msg)
        self.update()

    def paintlines(self, surface, first, count, l0):
        "draws the data out of the model onto the qpainter surface"
        self.model.cur = first
        N = self.model.linesize
        h = self.line.height
        ww = surface.window().width()
        y = (first - l0) * h
        c0, c1 = brushes.xv_bg, brushes.xv_bg_alt
        pen = surface.pen()
        for address, data, txt in self.model.iterlines(count):
            # background rect (alternate)
            r = QRect(0, y, ww, h)
            surface.fillRect(r, c0)
            # address column:
            r.setWidth(self.line.x_hex)
            surface.drawText(r, Qt.AlignHCenter | Qt.AlignVCenter,
                             "%08x" % address)
            # hex column:
            w = self.line.xb.width
            r.setWidth(w)
            r.translate(self.line.x_hex + self.line.pxpad, 0)
            C = self.highlight.get(address, [None] * N)
            for i, c in enumerate(C):
                try:
                    s = "%02x" % (data[i])
                except IndexError:
                    break
                flg = Qt.AlignHCenter | Qt.AlignVCenter
                if c:
                    surface.fillRect(r, c)
                    surface.setPen(QPen(Qt.white))
                surface.drawText(r, flg, s)
                surface.setPen(pen)
                r.translate(w, 0)
            # ascii column:
            w = self.line.xb.cw
            r.setX(self.line.x_txt + self.line.pxpad)
            r.setWidth(w)
            for i, c in enumerate(C):
                try:
                    s = txt[i]
                except IndexError:
                    break
                flg = Qt.AlignHCenter | Qt.AlignVCenter
                if c:
                    surface.fillRect(r, c)
                    surface.setPen(QPen(Qt.white))
                surface.drawText(r, flg, s)
                surface.setPen(pen)
                r.translate(w, 0)
            # clear background endline:
            r.setX(self.line.x_end)
            r.setWidth(ww - self.line.x_end)
            surface.fillRect(r, brushes.xv_bg_alt)
            y += h
            c0, c1 = c1, c0

    def paintframes(self, surface):
        r = surface.window()
        ww = surface.window().width()
        # top & bottom lines:
        surface.drawLine(0, r.top(), ww, r.top())
        surface.drawLine(0, r.bottom(), ww, r.bottom())
        # vertical column lines:
        x = self.line.x_hex
        surface.drawLine(x, r.top(), x, r.bottom())
        x = self.line.x_txt
        surface.drawLine(x, r.top(), x, r.bottom())
        x = self.line.x_end
        surface.drawLine(x, r.top(), x, r.bottom())

    def paintmap(self, surface):
        ww = surface.window().width()
        wh = surface.window().height()
        self.vb.setMaximum(self.qimg.height() - (wh // self.line.height))
        self.line.x_map = ww - 32
        r = QRect(self.line.x_map, 2, 32, wh - 4)
        surface.drawImage(r, self.qimg)
        factor = wh / self.qimg.height()
        pen = surface.pen()
        p = QPen(Qt.white)
        p.setCapStyle(Qt.RoundCap)
        p.setWidth(2)
        surface.setPen(p)
        l0 = self.vb.value() * factor
        l1 = l0 + (wh // self.line.height) * factor
        pad = 4
        p1 = QPointF(self.line.x_map - pad, l0)
        p2 = QPointF(self.line.x_map - pad, l1)
        if l1 - l0 > 4:
            p.setWidth(2)
            surface.drawLine(p1, p2)
            surface.drawLine(p1, QPointF(self.line.x_map, l0))
            surface.drawLine(p2, QPointF(self.line.x_map, l1))
        else:
            p.setWidth(4)
            surface.drawLine(p1, p2)
        surface.setPen(pen)

    def move(self, cur, e):
        return None

    def action(self, cur, e):
        return None