Beispiel #1
0
    def draw_histogram(self, height: int = 170, fill: int = 170):
        """
        Draw a histogram (RGB) from self.__pixbuf and return it as another pixbuf.

        :param height: height of the returned pixbuf
        :param fill: determines the color intensity of the filled graphs,
               valid values are between 0 and 255.
        :returns: modified pixbuf, the returned prixbuf will be 262x<height> px.
        """

        self.__pixbuf = ImageTools.static_image(self.__pixbuf)

        im = Image.new('RGB', (258, height - 4), (30, 30, 30))
        hist_data = ImageTools.pixbuf_to_pil(self.__pixbuf).histogram()
        maximum = max(hist_data[:768] + [1])
        y_scale = (height - 6) / maximum
        r = [int(hist_data[n] * y_scale) for n in range(256)]
        g = [int(hist_data[n] * y_scale) for n in range(256, 512)]
        b = [int(hist_data[n] * y_scale) for n in range(512, 768)]
        im_data = im.getdata()

        # Draw the filling colors
        for x in range(256):
            for y in range(1, max(r[x], g[x], b[x]) + 1):
                r_px = fill if y <= r[x] else 0
                g_px = fill if y <= g[x] else 0
                b_px = fill if y <= b[x] else 0
                im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, b_px))

        # Draw the outlines
        for x in range(1, 256):
            self._im_putpixel(x=x, channel=r, height=height, im_data=im_data)
            self._im_putpixel(x=x, channel=g, height=height, im_data=im_data)
            self._im_putpixel(x=x, channel=b, height=height, im_data=im_data)

        if config['ENHANCE_EXTRA']:
            # if True a label with the maximum pixel value will be added to one corner
            maxstr = f'max pixel value: {maximum}'
            draw = ImageDraw.Draw(im)
            draw.rectangle((0, 0, len(maxstr) * 6 + 2, 10), fill=(30, 30, 30))
            draw.text((2, 0), maxstr, fill=(255, 255, 255))

        im = ImageOps.expand(im, 1, (80, 80, 80))
        im = ImageOps.expand(im, 1, (0, 0, 0))

        self.__hist_image.set_from_pixbuf(ImageTools.pil_to_pixbuf(im))
Beispiel #2
0
    def _add_subpixbuf(self, canvas, x: int, y: int, image_size: tuple, source_pixbuf):
        """
        Copy a subpixbuf from <source_pixbuf> to <canvas> as it should
        be in the lens if the coordinates <x>, <y> are the mouse pointer
        position on the main window layout area.
        The displayed image (scaled from the <source_pixbuf>) must have
        size <image_size>
        """

        # Prevent division by zero exceptions further down
        if not image_size[0]:
            return

        # FIXME This merely prevents Errors being raised if source_pixbuf is an
        # animation. The result might be broken, though, since animation,
        # rotation etc. might not match or will be ignored:
        source_pixbuf = ImageTools.static_image(source_pixbuf)

        rotation = config['ROTATION']
        if config['AUTO_ROTATE_FROM_EXIF']:
            rotation += ImageTools.get_implied_rotation(source_pixbuf)
            rotation %= 360

        if rotation in (90, 270):
            scale = source_pixbuf.get_height() / image_size[0]
        else:
            scale = source_pixbuf.get_width() / image_size[0]

        x *= scale
        y *= scale

        source_mag = config['LENS_MAGNIFICATION'] / scale
        width = height = config['LENS_SIZE'] / source_mag

        paste_left = x > width / 2
        paste_top = y > height / 2
        dest_x = max(0, int(math.ceil((width / 2 - x) * source_mag)))
        dest_y = max(0, int(math.ceil((height / 2 - y) * source_mag)))

        if rotation == 90:
            x, y = y, source_pixbuf.get_height() - x
        elif rotation == 180:
            x = source_pixbuf.get_width() - x
            y = source_pixbuf.get_height() - y
        elif rotation == 270:
            x, y = source_pixbuf.get_width() - y, x

        if config['HORIZONTAL_FLIP']:
            if rotation in (90, 270):
                y = source_pixbuf.get_height() - y
            else:
                x = source_pixbuf.get_width() - x
        if config['VERTICAL_FLIP']:
            if rotation in (90, 270):
                x = source_pixbuf.get_width() - x
            else:
                y = source_pixbuf.get_height() - y

        src_x = x - width / 2
        src_y = y - height / 2
        if src_x < 0:
            width += src_x
            src_x = 0
        if src_y < 0:
            height += src_y
            src_y = 0
        width = max(0, min(source_pixbuf.get_width() - src_x, width))
        height = max(0, min(source_pixbuf.get_height() - src_y, height))
        if width < 1 or height < 1:
            return

        subpixbuf = source_pixbuf.new_subpixbuf(int(src_x), int(src_y), int(width), int(height))
        subpixbuf = subpixbuf.scale_simple(
            int(math.ceil(source_mag * subpixbuf.get_width())),
            int(math.ceil(source_mag * subpixbuf.get_height())),
            config['SCALING_QUALITY'])

        if rotation == 0:
            subpixbuf = subpixbuf.rotate_simple(GdkPixbuf.PixbufRotation.NONE)
        elif rotation == 90:
            subpixbuf = subpixbuf.rotate_simple(GdkPixbuf.PixbufRotation.CLOCKWISE)
        elif rotation == 180:
            subpixbuf = subpixbuf.rotate_simple(GdkPixbuf.PixbufRotation.UPSIDEDOWN)
        elif rotation == 270:
            subpixbuf = subpixbuf.rotate_simple(GdkPixbuf.PixbufRotation.COUNTERCLOCKWISE)

        if config['HORIZONTAL_FLIP']:
            subpixbuf = subpixbuf.flip(horizontal=True)
        if config['VERTICAL_FLIP']:
            subpixbuf = subpixbuf.flip(horizontal=False)

        subpixbuf = self.__window.enhancer.enhance(subpixbuf)

        if paste_left:
            dest_x = 0
        else:
            dest_x = min(canvas.get_width() - subpixbuf.get_width(), dest_x)
        if paste_top:
            dest_y = 0
        else:
            dest_y = min(canvas.get_height() - subpixbuf.get_height(), dest_y)

        if subpixbuf.get_has_alpha() and config['CHECKERED_BG_FOR_TRANSPARENT_IMAGES']:
            subpixbuf = subpixbuf.composite_color_simple(subpixbuf.get_width(), subpixbuf.get_height(),
                                                         GdkPixbuf.InterpType.NEAREST, 255, 8, 0x777777, 0x999999)

        subpixbuf.copy_area(0, 0, subpixbuf.get_width(), subpixbuf.get_height(), canvas, dest_x, dest_y)
Beispiel #3
0
    def _add_subpixbuf(self, canvas, x: int, y: int, image_size: tuple, source_pixbuf):
        """
        Copy a subpixbuf from <source_pixbuf> to <canvas> as it should
        be in the lens if the coordinates <x>, <y> are the mouse pointer
        position on the main window layout area.
        The displayed image (scaled from the <source_pixbuf>) must have
        size <image_size>
        """

        # Prevent division by zero exceptions further down
        if not image_size[0]:
            return

        # FIXME This merely prevents Errors being raised if source_pixbuf is an
        # animation. The result might be broken, though, since animation,
        # rotation etc. might not match or will be ignored:
        source_pixbuf = ImageTools.static_image(source_pixbuf)

        rotation = config['ROTATION']
        if config['AUTO_ROTATE_FROM_EXIF']:
            rotation += ImageTools.get_implied_rotation(source_pixbuf)
            rotation %= 360

        if rotation in (90, 270):
            scale = source_pixbuf.get_height() / image_size[0]
        else:
            scale = source_pixbuf.get_width() / image_size[0]

        x *= scale
        y *= scale

        source_mag = config['LENS_MAGNIFICATION'] / scale
        width = height = config['LENS_SIZE'] / source_mag

        paste_left = x > width / 2
        paste_top = y > height / 2
        dest_x = max(0, int(math.ceil((width / 2 - x) * source_mag)))
        dest_y = max(0, int(math.ceil((height / 2 - y) * source_mag)))

        match rotation:
            case 90:
                x, y = y, source_pixbuf.get_height() - x
            case 180:
                x = source_pixbuf.get_width() - x
                y = source_pixbuf.get_height() - y
            case 270:
                x, y = source_pixbuf.get_width() - y, x

        src_x = x - width / 2
        src_y = y - height / 2
        if src_x < 0:
            width += src_x
            src_x = 0
        if src_y < 0:
            height += src_y
            src_y = 0
        width = max(0, min(source_pixbuf.get_width() - src_x, width))
        height = max(0, min(source_pixbuf.get_height() - src_y, height))
        if width < 1 or height < 1:
            return

        subpixbuf = source_pixbuf.new_subpixbuf(int(src_x), int(src_y), int(width), int(height))
        subpixbuf = subpixbuf.scale_simple(
            int(math.ceil(source_mag * subpixbuf.get_width())),
            int(math.ceil(source_mag * subpixbuf.get_height())),
            config['GDK_SCALING_FILTER'])

        subpixbuf = ImageTools.rotate_pixbuf(subpixbuf, rotation)
        subpixbuf = ImageTools.enhance(subpixbuf)

        if paste_left:
            dest_x = 0
        else:
            dest_x = min(canvas.get_width() - subpixbuf.get_width(), dest_x)
        if paste_top:
            dest_y = 0
        else:
            dest_y = min(canvas.get_height() - subpixbuf.get_height(), dest_y)

        if subpixbuf.get_has_alpha():
            subpixbuf = ImageTools.add_alpha_background(subpixbuf, subpixbuf.get_width(), subpixbuf.get_height())

        subpixbuf.copy_area(0, 0, subpixbuf.get_width(), subpixbuf.get_height(), canvas, dest_x, dest_y)