Ejemplo n.º 1
0
 def test_fit_in_rectangle_transparent_no_resize(self):
     # And with a transparent test image, check alpha blending.
     image = 'pattern-transparent-rgba.png'
     control = Image.open(get_image_path(image))
     # Create checkerboard background.
     checker_bg = Image.new('RGBA', control.size)
     checker = Image.open(get_image_path('checkerboard.png'))
     for x in range(0, control.size[0], checker.size[0]):
         for y in range(0, control.size[1], checker.size[1]):
             checker_bg.paste(checker, (x, y))
     # Create whhite background.
     white_bg = Image.new('RGBA', control.size, color='white')
     assert control.size == white_bg.size
     width, height = control.size
     for use_checker_bg in (False, True):
         prefs['checkered bg for transparent images'] = use_checker_bg
         expected = Image.alpha_composite(
             checker_bg if use_checker_bg else white_bg, control)
         for scaling_quality in range(4):
             prefs['scaling quality'] = scaling_quality
             result = image_tools.fit_in_rectangle(
                 image_tools.pil_to_pixbuf(control),
                 width,
                 height,
                 scaling_quality=scaling_quality)
             msg = (
                 'fit_in_rectangle("%s", scaling quality=%d, background=%s) failed; '
                 'result %%(diff_type)s differs: %%(diff)s' %
                 (image, scaling_quality,
                  'checker' if checker_bg else 'white'))
             self.assertImagesEqual(result, expected, msg=msg)
Ejemplo n.º 2
0
 def test_fit_in_rectangle_transparent_no_resize(self):
     # And with a transparent test image, check alpha blending.
     image = 'pattern-transparent-rgba.png'
     control = Image.open(get_image_path(image))
     # Create checkerboard background.
     checker_bg = Image.new('RGBA', control.size)
     checker = Image.open(get_image_path('checkerboard.png'))
     for x in range(0, control.size[0], checker.size[0]):
         for y in range(0, control.size[1], checker.size[1]):
             checker_bg.paste(checker, (x, y))
     # Create whhite background.
     white_bg = Image.new('RGBA', control.size, color='white')
     assert control.size == white_bg.size
     width, height = control.size
     for use_checker_bg in (False, True):
         prefs['checkered bg for transparent images'] = use_checker_bg
         expected = Image.alpha_composite(
             checker_bg if use_checker_bg else white_bg,
             control
         )
         for scaling_quality in range(4):
             prefs['scaling quality'] = scaling_quality
             result = image_tools.fit_in_rectangle(image_tools.pil_to_pixbuf(control),
                                                   width, height,
                                                   scaling_quality=scaling_quality)
             msg = (
                 'fit_in_rectangle("%s", scaling quality=%d, background=%s) failed; '
                 'result %%(diff_type)s differs: %%(diff)s'
                 % (image, scaling_quality, 'checker' if checker_bg else 'white')
             )
             self.assertImagesEqual(result, expected, msg=msg)
Ejemplo n.º 3
0
 def test_pil_to_pixbuf(self):
     base_im = Image.open(get_image_path('transparent.png'))
     for _, expected_pixbuf_mode, mode in _IMAGE_MODES:
         input_im = base_im.convert(mode)
         pixbuf = image_tools.pil_to_pixbuf(input_im)
         expected_im = input_im.convert(expected_pixbuf_mode)
         msg = ('pil_to_pixbuf("%s") failed; '
                'result %%(diff_type)s differs: %%(diff)s' % (mode, ))
         self.assertImagesEqual(pixbuf, expected_im, msg=msg)
Ejemplo n.º 4
0
def draw_histogram(pixbuf, height=170, fill=170, text=True):
    """Draw a histogram from <pixbuf> and return it as another pixbuf.

    The returned prixbuf will be 262x<height> px.

    The value of <fill> determines the colour intensity of the filled graphs,
    valid values are between 0 and 255.

    If <text> is True a label with the maximum pixel value will be added to
    one corner.
    """
    im = Image.new('RGB', (258, height - 4), (30, 30, 30))
    hist_data = image_tools.pixbuf_to_pil(pixbuf).histogram()
    maximum = max(hist_data[:768] + [1])
    y_scale = float(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 colours
    for x in range(256):
        for y in range(1, max(r[x], g[x], b[x]) + 1):
            r_px = y <= r[x] and fill or 0
            g_px = y <= g[x] and fill or 0
            b_px = y <= b[x] and fill or 0
            im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, b_px))
    # Draw the outlines
    for x in range(1, 256):
        for y in range(r[x - 1] + 1, r[x] + 1) + [r[x]] * (r[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (255, g_px, b_px))
        for y in range(r[x] + 1, r[x - 1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (255, g_px, b_px))
        for y in range(g[x - 1] + 1, g[x] + 1) + [g[x]] * (g[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (r_px, 255, b_px))
        for y in range(g[x] + 1, g[x - 1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (r_px, 255, b_px))
        for y in range(b[x - 1] + 1, b[x] + 1) + [b[x]] * (b[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, 255))
        for y in range(b[x] + 1, b[x - 1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (r_px, g_px, 255))
    if text:
        maxstr = 'max: ' + str(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))
    return image_tools.pil_to_pixbuf(im)
Ejemplo n.º 5
0
def draw_histogram(pixbuf, height=170, fill=170, text=True):
    """Draw a histogram from <pixbuf> and return it as another pixbuf.

    The returned prixbuf will be 262x<height> px.

    The value of <fill> determines the colour intensity of the filled graphs,
    valid values are between 0 and 255.

    If <text> is True a label with the maximum pixel value will be added to
    one corner.
    """
    im = Image.new('RGB', (258, height - 4), (30, 30, 30))
    hist_data = image_tools.pixbuf_to_pil(pixbuf).histogram()
    maximum = max(hist_data[:768] + [1])
    y_scale = float(height - 6) / maximum
    r = [int(hist_data[n] * y_scale) for n in xrange(256)]
    g = [int(hist_data[n] * y_scale) for n in xrange(256, 512)]
    b = [int(hist_data[n] * y_scale) for n in xrange(512, 768)]
    im_data = im.getdata()
    # Draw the filling colours
    for x in xrange(256):
        for y in xrange(1, max(r[x], g[x], b[x]) + 1):
            r_px = y <= r[x] and fill or 0
            g_px = y <= g[x] and fill or 0
            b_px = y <= b[x] and fill or 0
            im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, b_px))
    # Draw the outlines
    for x in xrange(1, 256):
        for y in range(r[x-1] + 1, r[x] + 1) + [r[x]] * (r[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (255, g_px, b_px))
        for y in range(r[x] + 1, r[x-1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (255, g_px, b_px))
        for y in range(g[x-1] + 1, g[x] + 1) + [g[x]] * (g[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (r_px, 255, b_px))
        for y in range(g[x] + 1, g[x-1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (r_px, 255, b_px))
        for y in range(b[x-1] + 1, b[x] + 1) + [b[x]] * (b[x] != 0):
            r_px, g_px, b_px = im_data.getpixel((x + 1, height - 5 - y))
            im_data.putpixel((x + 1, height - 5 - y), (r_px, g_px, 255))
        for y in range(b[x] + 1, b[x-1] + 1):
            r_px, g_px, b_px = im_data.getpixel((x, height - 5 - y))
            im_data.putpixel((x, height - 5 - y), (r_px, g_px, 255))
    if text:
        maxstr = 'max: ' + str(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))
    return image_tools.pil_to_pixbuf(im)
Ejemplo n.º 6
0
 def test_pil_to_pixbuf(self):
     base_im = Image.open(get_image_path('transparent.png'))
     for _, expected_pixbuf_mode, mode in _IMAGE_MODES:
         input_im = base_im.convert(mode)
         pixbuf = image_tools.pil_to_pixbuf(input_im)
         expected_im = input_im.convert(expected_pixbuf_mode)
         msg = (
             'pil_to_pixbuf("%s") failed; '
             'result %%(diff_type)s differs: %%(diff)s'
             % (mode,)
         )
         self.assertImagesEqual(pixbuf, expected_im, msg=msg)
Ejemplo n.º 7
0
    def _drag_begin(self, iconview, context):
        """Create a cursor image for drag-n-drop from the library.

        This method relies on implementation details regarding PIL's
        drawing functions and default font to produce good looking results.
        If those are changed in a future release of PIL, this method might
        produce bad looking output (e.g. non-centered text).

        It's also used with connect_after() to overwrite the cursor
        automatically created when using enable_model_drag_source(), so in
        essence it's a hack, but at least it works.
        """
        icon_path = iconview.get_cursor()[0]
        num_books = len(iconview.get_selected_items())
        book = self.get_book_at_path(icon_path)

        cover = self._library.backend.get_book_cover(book)
        if cover is None:
            cover = image_tools.MISSING_IMAGE_ICON

        cover = cover.scale_simple(max(0, cover.get_width() // 2),
            max(0, cover.get_height() // 2), prefs['scaling quality'])
        cover = image_tools.add_border(cover, 1, 0xFFFFFFFF)
        cover = image_tools.add_border(cover, 1)

        if num_books > 1:
            cover_width = cover.get_width()
            cover_height = cover.get_height()
            pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
                max(30, cover_width + 15), max(30, cover_height + 10))
            pointer.fill(0x00000000)
            cover.composite(pointer, 0, 0, cover_width, cover_height, 0, 0,
            1, 1, prefs['scaling quality'], 255)
            im = Image.new('RGBA', (30, 30), 0x00000000)
            draw = ImageDraw.Draw(im)
            draw.polygon(
                (8, 0, 20, 0, 28, 8, 28, 20, 20, 28, 8, 28, 0, 20, 0, 8),
                fill=(0, 0, 0), outline=(0, 0, 0))
            draw.polygon(
                (8, 1, 20, 1, 27, 8, 27, 20, 20, 27, 8, 27, 1, 20, 1, 8),
                fill=(128, 0, 0), outline=(255, 255, 255))
            text = str(num_books)
            draw.text((15 - (6 * len(text) // 2), 9), text,
                fill=(255, 255, 255))
            circle = image_tools.pil_to_pixbuf(im)
            circle.composite(pointer, max(0, cover_width - 15),
                max(0, cover_height - 20), 30, 30, max(0, cover_width - 15),
                max(0, cover_height - 20), 1, 1, prefs['scaling quality'], 255)
        else:
            pointer = cover

        context.set_icon_pixbuf(pointer, -5, -5)
Ejemplo n.º 8
0
    def _drag_begin(self, iconview, context):
        """Create a cursor image for drag-n-drop from the library.

        This method relies on implementation details regarding PIL's
        drawing functions and default font to produce good looking results.
        If those are changed in a future release of PIL, this method might
        produce bad looking output (e.g. non-centered text).

        It's also used with connect_after() to overwrite the cursor
        automatically created when using enable_model_drag_source(), so in
        essence it's a hack, but at least it works.
        """
        icon_path = iconview.get_cursor()[0]
        num_books = len(iconview.get_selected_items())
        book = self.get_book_at_path(icon_path)

        cover = self._library.backend.get_book_cover(book)
        if cover is None:
            cover = constants.MISSING_IMAGE_ICON

        cover = cover.scale_simple(max(0, cover.get_width() // 2),
            max(0, cover.get_height() // 2), prefs['scaling quality'])
        cover = image_tools.add_border(cover, 1, 0xFFFFFFFF)
        cover = image_tools.add_border(cover, 1)

        if num_books > 1:
            cover_width = cover.get_width()
            cover_height = cover.get_height()
            pointer = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
                max(30, cover_width + 15), max(30, cover_height + 10))
            pointer.fill(0x00000000)
            cover.composite(pointer, 0, 0, cover_width, cover_height, 0, 0,
            1, 1, prefs['scaling quality'], 255)
            im = Image.new('RGBA', (30, 30), 0x00000000)
            draw = ImageDraw.Draw(im)
            draw.polygon(
                (8, 0, 20, 0, 28, 8, 28, 20, 20, 28, 8, 28, 0, 20, 0, 8),
                fill=(0, 0, 0), outline=(0, 0, 0))
            draw.polygon(
                (8, 1, 20, 1, 27, 8, 27, 20, 20, 27, 8, 27, 1, 20, 1, 8),
                fill=(128, 0, 0), outline=(255, 255, 255))
            text = str(num_books)
            draw.text((15 - (6 * len(text) // 2), 9), text,
                fill=(255, 255, 255))
            circle = image_tools.pil_to_pixbuf(im)
            circle.composite(pointer, max(0, cover_width - 15),
                max(0, cover_height - 20), 30, 30, max(0, cover_width - 15),
                max(0, cover_height - 20), 1, 1, prefs['scaling quality'], 255)
        else:
            pointer = cover

        context.set_icon_pixbuf(pointer, -5, -5)
Ejemplo n.º 9
0
 def test_fit_in_rectangle_rotation(self):
     image_size = 128
     rect_size = 32
     # Start with a black image.
     im = Image.new('RGB', (image_size, image_size), color='black')
     draw = ImageDraw.Draw(im)
     # Paint top-left corner white.
     draw.rectangle((0, 0, rect_size, rect_size), fill='white')
     # Corner colors, starting top-left, rotating clock-wise.
     corners_colors = ('white', 'black', 'black', 'black')
     pixbuf = image_tools.pil_to_pixbuf(im)
     for rotation in (0, 90, 180, 270, -90, -180, -270, 90 * 5, -90 * 7):
         for target_size in (
             (image_size, image_size),
             (image_size / 2, image_size / 2),
         ):
             result = image_tools.fit_in_rectangle(pixbuf,
                                                   target_size[0],
                                                   target_size[1],
                                                   rotation=rotation)
             # First check size.
             input_size = (image_size, image_size)
             result_size = result.get_width(), result.get_height()
             msg = ('fit_in_rectangle(%dx%d => %dx%d, rotation=%d) failed; '
                    'result size: %dx%d' % (input_size + target_size +
                                            (rotation, ) + result_size))
             self.assertEqual(result_size, target_size, msg=msg)
             # And then check corners.
             expected_corners_colors = list(corners_colors)
             for _ in range(1, 1 + (rotation % 360) / 90):
                 expected_corners_colors.insert(
                     0, expected_corners_colors.pop(-1))
             result_corners_colors = []
             corner = new_pixbuf((1, 1), False, 0x888888)
             corners_positions = [
                 0, 0, target_size[0] - 1, target_size[0] - 1
             ]
             for _ in range(4):
                 x, y = corners_positions[0:2]
                 result.copy_area(x, y, 1, 1, corner, 0, 0)
                 color = corner.get_pixels()[0:3]
                 color = binascii.hexlify(color)
                 if 'ffffff' == color:
                     color = 'white'
                 elif '000000' == color:
                     color = 'black'
                 result_corners_colors.append(color)
                 corners_positions.insert(0, corners_positions.pop(-1))
             # Swap bottom corners for spatial display.
             result_corners_colors.append(result_corners_colors.pop(-2))
             expected_corners_colors.append(expected_corners_colors.pop(-2))
             msg = ('fit_in_rectangle(%dx%d => %dx%d, rotation=%d) failed; '
                    'result corners differs:\n'
                    '%s\t%s\n'
                    '%s\t%s\n'
                    'instead of:\n'
                    '%s\t%s\n'
                    '%s\t%s\n' %
                    (input_size + target_size +
                     (rotation, ) + tuple(result_corners_colors) +
                     tuple(expected_corners_colors)))
             self.assertEqual(result_corners_colors,
                              expected_corners_colors,
                              msg=msg)
Ejemplo n.º 10
0
 def test_fit_in_rectangle_rotation(self):
     image_size = 128
     rect_size = 32
     # Start with a black image.
     im = Image.new('RGB', (image_size, image_size), color='black')
     draw = ImageDraw.Draw(im)
     # Paint top-left corner white.
     draw.rectangle((0, 0, rect_size, rect_size), fill='white')
     # Corner colors, starting top-left, rotating clock-wise.
     corners_colors = ('white', 'black', 'black', 'black')
     pixbuf = image_tools.pil_to_pixbuf(im)
     for rotation in (
         0, 90, 180, 270,
         -90, -180, -270,
         90 * 5, -90 * 7
     ):
         for target_size in (
             (image_size, image_size),
             (image_size / 2, image_size / 2),
         ):
             result = image_tools.fit_in_rectangle(pixbuf,
                                                   target_size[0],
                                                   target_size[1],
                                                   rotation=rotation)
             # First check size.
             input_size = (image_size, image_size)
             result_size = result.get_width(), result.get_height()
             msg = (
                 'fit_in_rectangle(%dx%d => %dx%d, rotation=%d) failed; '
                 'result size: %dx%d' % (
                     input_size + target_size + (rotation,) + result_size
                 )
             )
             self.assertEqual(result_size, target_size, msg=msg)
             # And then check corners.
             expected_corners_colors = list(corners_colors)
             for _ in range(1, 1 + (rotation % 360) / 90):
                 expected_corners_colors.insert(0, expected_corners_colors.pop(-1))
             result_corners_colors = []
             corner = new_pixbuf((1, 1), False, 0x888888)
             corners_positions = [0, 0, target_size[0] - 1, target_size[0] - 1]
             for _ in range(4):
                 x, y = corners_positions[0:2]
                 result.copy_area(x, y, 1, 1, corner, 0, 0)
                 color = corner.get_pixels()[0:3]
                 color = binascii.hexlify(color)
                 if 'ffffff' == color:
                     color = 'white'
                 elif '000000' == color:
                     color = 'black'
                 result_corners_colors.append(color)
                 corners_positions.insert(0, corners_positions.pop(-1))
             # Swap bottom corners for spatial display.
             result_corners_colors.append(result_corners_colors.pop(-2))
             expected_corners_colors.append(expected_corners_colors.pop(-2))
             msg = (
                 'fit_in_rectangle(%dx%d => %dx%d, rotation=%d) failed; '
                 'result corners differs:\n'
                 '%s\t%s\n'
                 '%s\t%s\n'
                 'instead of:\n'
                 '%s\t%s\n'
                 '%s\t%s\n' % (
                     input_size + target_size + (rotation, ) +
                     tuple(result_corners_colors) +
                     tuple(expected_corners_colors)
                 )
             )
             self.assertEqual(result_corners_colors,
                              expected_corners_colors,
                              msg=msg)