Exemplo n.º 1
0
    def thumbnail(self, filepath, mt=False):
        ''' Returns a thumbnail pixbuf for <filepath>, transparently handling
        both normal image files and archives. If a thumbnail file already exists,
        it is re-used. Otherwise, a new thumbnail is created from <filepath>.

        Returns None if thumbnail creation failed, or if the thumbnail creation
        is run asynchrounosly. '''

        # Update width and height from preferences if they haven't been set explicitly
        if self.default_sizes:
            self.width = prefs['thumbnail size']
            self.height = prefs['thumbnail size']

        if self._thumbnail_exists(filepath):
            thumbpath = self._path_to_thumbpath(filepath)
            pixbuf = image_tools.load_pixbuf(thumbpath)
            self.thumbnail_finished(filepath, pixbuf)
            return pixbuf

        else:
            if mt:
                thread = threading.Thread(target=self._create_thumbnail,
                                          args=(filepath, ))
                thread.name += '-thumbnailer'
                thread.daemon = True
                thread.start()
                return None
            else:
                return self._create_thumbnail(filepath)
Exemplo n.º 2
0
 def test_pixbuf_to_pil(self):
     for image in (
             'transparent.png',
             'transparent-indexed.png',
             'pattern-opaque-rgb.png',
             'pattern-opaque-rgba.png',
             'pattern-transparent-rgba.png',
     ):
         pixbuf = image_tools.load_pixbuf(get_image_path(image))
         im = image_tools.pixbuf_to_pil(pixbuf)
         msg = ('pixbuf_to_pil("%s") failed; '
                'result %%(diff_type)s differs: %%(diff)s' % (image, ))
         self.assertImagesEqual(im, pixbuf, msg=msg)
Exemplo n.º 3
0
 def test_load_pixbuf_basic(self):
     for image in _TEST_IMAGES:
         image_path = get_image_path(image.name)
         if self.use_pil:
             # When using PIL, indexed formats will be
             # converted to RGBA by pixbuf_to_pil.
             expected_mode = pil_mode_to_gdk_mode(image.mode)
         else:
             expected_mode = 'RGBA' if image.has_alpha else 'RGB'
         im = Image.open(image_path).convert(expected_mode)
         pixbuf = image_tools.load_pixbuf(image_path)
         msg = ('load_pixbuf("%s") failed; '
                'result %%(diff_type)s differs: %%(diff)s' % (image.name, ))
         self.assertImagesEqual(pixbuf, im, msg=msg)
Exemplo n.º 4
0
 def test_fit_in_rectangle_opaque_no_resize(self):
     # Check opaque image is unchanged when not resizing.
     for image in (
             'pattern-opaque-rgb.png',
             'pattern-opaque-rgba.png',
     ):
         input = image_tools.load_pixbuf(get_image_path(image))
         width, height = input.get_width(), input.get_height()
         for scaling_quality in range(4):
             prefs['scaling quality'] = scaling_quality
             result = image_tools.fit_in_rectangle(
                 input, width, height, scaling_quality=scaling_quality)
             msg = ('fit_in_rectangle("%s", scaling quality=%d) failed; '
                    'result %%(diff_type)s differs: %%(diff)s' %
                    (image, scaling_quality))
             self.assertImagesEqual(result, input, msg=msg)
Exemplo n.º 5
0
 def test_load_pixbuf_modes(self):
     tmp_file = tempfile.NamedTemporaryFile(prefix=u'image.',
                                            suffix=u'.png',
                                            delete=False)
     tmp_file.close()
     base_im = Image.open(get_image_path('transparent.png'))
     for supported, expected_pixbuf_mode, mode in _IMAGE_MODES:
         if not supported:
             continue
         input_im = base_im.convert(mode)
         input_im.save(tmp_file.name)
         pixbuf = image_tools.load_pixbuf(tmp_file.name)
         expected_im = input_im.convert(expected_pixbuf_mode)
         msg = ('load_pixbuf("%s") failed; '
                'result %%(diff_type)s differs: %%(diff)s' % (mode, ))
         self.assertImagesEqual(pixbuf, expected_im, msg=msg)
Exemplo n.º 6
0
 def _cache_pixbuf(self, index, force=False):
     self._wait_on_page(index + 1)
     with self._cache_lock[index]:
         if index in self._raw_pixbufs:
             return
         with self._lock:
             if not force and index not in self._wanted_pixbufs:
                 return
         log.debug('Caching page %u', index + 1)
         try:
             pixbuf = image_tools.load_pixbuf(self._image_files[index])
             tools.garbage_collect()
         except Exception as e:
             log.error('Could not load pixbuf for page %u: %r', index + 1, e)
             pixbuf = image_tools.MISSING_IMAGE_ICON
         self._raw_pixbufs[index] = pixbuf
Exemplo n.º 7
0
 def test_pixbuf_to_pil(self):
     for image in (
         'transparent.png',
         'transparent-indexed.png',
         'pattern-opaque-rgb.png',
         'pattern-opaque-rgba.png',
         'pattern-transparent-rgba.png',
     ):
         pixbuf = image_tools.load_pixbuf(get_image_path(image))
         im = image_tools.pixbuf_to_pil(pixbuf)
         msg = (
             'pixbuf_to_pil("%s") failed; '
             'result %%(diff_type)s differs: %%(diff)s'
             % (image,)
         )
         self.assertImagesEqual(im, pixbuf, msg=msg)
Exemplo n.º 8
0
    def _get_pixbuf(self, index):
        """Return the pixbuf indexed by <index> from cache.
        Pixbufs not found in cache are fetched from disk first.
        """
        pixbuf = constants.MISSING_IMAGE_ICON

        if index not in self._raw_pixbufs:
            self._wait_on_page(index + 1)

            try:
                pixbuf = image_tools.load_pixbuf(self._image_files[index])
                self._raw_pixbufs[index] = pixbuf
                tools.garbage_collect()
            except Exception, e:
                self._raw_pixbufs[index] = constants.MISSING_IMAGE_ICON
                log.debug('Could not load pixbuf for page %d: %r', index, e)
Exemplo n.º 9
0
    def _get_pixbuf(self, index):
        """Return the pixbuf indexed by <index> from cache.
        Pixbufs not found in cache are fetched from disk first.
        """
        pixbuf = image_tools.MISSING_IMAGE_ICON

        if index not in self._raw_pixbufs:
            self._wait_on_page(index + 1)

            try:
                pixbuf = image_tools.load_pixbuf(self._image_files[index])
                self._raw_pixbufs[index] = pixbuf
                tools.garbage_collect()
            except Exception, e:
                self._raw_pixbufs[index] = image_tools.MISSING_IMAGE_ICON
                log.error('Could not load pixbuf for page %u: %r', index + 1, e)
Exemplo n.º 10
0
 def test_load_pixbuf_basic(self):
     for image in _TEST_IMAGES:
         image_path = get_image_path(image.name)
         if self.use_pil:
             # When using PIL, indexed formats will be
             # converted to RGBA by pixbuf_to_pil.
             expected_mode = pil_mode_to_gdk_mode(image.mode)
         else:
             expected_mode = 'RGBA' if image.has_alpha else 'RGB'
         im = Image.open(image_path).convert(expected_mode)
         pixbuf = image_tools.load_pixbuf(image_path)
         msg = (
             'load_pixbuf("%s") failed; '
             'result %%(diff_type)s differs: %%(diff)s'
             % (image.name,)
         )
         self.assertImagesEqual(pixbuf, im, msg=msg)
Exemplo n.º 11
0
 def test_fit_in_rectangle_opaque_no_resize(self):
     # Check opaque image is unchanged when not resizing.
     for image in (
         'pattern-opaque-rgb.png',
         'pattern-opaque-rgba.png',
     ):
         input = image_tools.load_pixbuf(get_image_path(image))
         width, height = input.get_width(), input.get_height()
         for scaling_quality in range(4):
             prefs['scaling quality'] = scaling_quality
             result = image_tools.fit_in_rectangle(input, width, height,
                                                   scaling_quality=scaling_quality)
             msg = (
                 'fit_in_rectangle("%s", scaling quality=%d) failed; '
                 'result %%(diff_type)s differs: %%(diff)s'
                 % (image, scaling_quality)
             )
             self.assertImagesEqual(result, input, msg=msg)
Exemplo n.º 12
0
 def test_load_pixbuf_modes(self):
     tmp_file = tempfile.NamedTemporaryFile(prefix=u'image.',
                                            suffix=u'.png', delete=False)
     tmp_file.close()
     base_im = Image.open(get_image_path('transparent.png'))
     for supported, expected_pixbuf_mode, mode in _IMAGE_MODES:
         if not supported:
             continue
         input_im = base_im.convert(mode)
         input_im.save(tmp_file.name)
         pixbuf = image_tools.load_pixbuf(tmp_file.name)
         expected_im = input_im.convert(expected_pixbuf_mode)
         msg = (
             'load_pixbuf("%s") failed; '
             'result %%(diff_type)s differs: %%(diff)s'
             % (mode,)
         )
         self.assertImagesEqual(pixbuf, expected_im, msg=msg)
Exemplo n.º 13
0
 def test_get_implied_rotation(self):
     for name in (
         # JPEG.
         'landscape-exif-270-rotation.jpg',
         'landscape-no-exif.jpg',
         'portrait-exif-180-rotation.jpg',
         'portrait-no-exif.jpg',
         # PNG.
         'landscape-exif-270-rotation.png',
         'landscape-no-exif.png',
         'portrait-exif-180-rotation.png',
         'portrait-no-exif.png',
     ):
         image = get_test_image(name)
         pixbuf = image_tools.load_pixbuf(get_image_path(name))
         rotation = image_tools.get_implied_rotation(pixbuf)
         self.assertEqual(rotation, image.rotation,
                          msg='get_implied_rotation(%s) failed: %u instead of %u'
                          % (image, rotation, image.rotation))
Exemplo n.º 14
0
 def test_get_implied_rotation(self):
     for name in (
         # JPEG.
         'landscape-exif-270-rotation.jpg',
         'landscape-no-exif.jpg',
         'portrait-exif-180-rotation.jpg',
         'portrait-no-exif.jpg',
         # PNG.
         'landscape-exif-270-rotation.png',
         'landscape-no-exif.png',
         'portrait-exif-180-rotation.png',
         'portrait-no-exif.png',
     ):
         image = get_test_image(name)
         pixbuf = image_tools.load_pixbuf(get_image_path(name))
         rotation = image_tools.get_implied_rotation(pixbuf)
         self.assertEqual(rotation, image.rotation,
                          msg='get_implied_rotation(%s) failed: %u instead of %u'
                          % (image, rotation, image.rotation))
Exemplo n.º 15
0
    def _get_pixbuf(self, index):
        """Return the pixbuf indexed by <index> from cache.
        Pixbufs not found in cache are fetched from disk first.
        """
        pixbuf = constants.MISSING_IMAGE_ICON

        if index not in self._raw_pixbufs:
            self._wait_on_page(index + 1)

            try:
                pixbuf = image_tools.load_pixbuf(self._image_files[index])
                self._raw_pixbufs[index] = pixbuf
            except Exception:
                self._raw_pixbufs[index] = constants.MISSING_IMAGE_ICON
        else:
            try:
                pixbuf = self._raw_pixbufs[index]
            except Exception:
                pass

        return pixbuf
Exemplo n.º 16
0
    def _get_pixbuf(self, index):
        """Return the pixbuf indexed by <index> from cache.
        Pixbufs not found in cache are fetched from disk first.
        """
        pixbuf = constants.MISSING_IMAGE_ICON

        if index not in self._raw_pixbufs:
            self._wait_on_page(index + 1)

            try:
                pixbuf = image_tools.load_pixbuf(self._image_files[index])
                self._raw_pixbufs[index] = pixbuf
            except Exception:
                self._raw_pixbufs[index] = constants.MISSING_IMAGE_ICON
        else:
            try:
                pixbuf = self._raw_pixbufs[index]
            except Exception:
                pass

        return pixbuf
Exemplo n.º 17
0
class Thumbnailer(object):
    """ The Thumbnailer class is responsible for managing MComix
    internal thumbnail creation. Depending on its settings,
    it either stores thumbnails on disk and retrieves them later,
    or simply creates new thumbnails each time it is called. """
    def __init__(self,
                 dst_dir=constants.THUMBNAIL_PATH,
                 store_on_disk=None,
                 size=None,
                 force_recreation=False,
                 archive_support=False):
        """
        <dst_dir> set the thumbnailer's storage directory.

        If <store_on_disk> on disk is True, it changes the thumbnailer's
        behaviour to store files on disk, or just create new thumbnails each
        time it was called when set to False. Defaults to the 'create
        thumbnails' preference if not set.

        The dimensions for the created thumbnails is set by <size>, a (width,
        height) tupple. Defaults to the 'thumbnail size' preference if not set.

        If <force_recreation> is True, thumbnails stored on disk
        will always be re-created instead of being re-used.

        If <archive_support> is True, support for archive thumbnail creation
        (based on cover detection) is enabled. Otherwise, only image files are
        supported.
        """
        self.dst_dir = dst_dir
        if store_on_disk is None:
            self.store_on_disk = prefs['create thumbnails']
        else:
            self.store_on_disk = store_on_disk
        if size is None:
            self.width = self.height = prefs['thumbnail size']
            self.default_sizes = True
        else:
            self.width, self.height = size
            self.default_sizes = False
        self.force_recreation = force_recreation
        self.archive_support = archive_support

    def thumbnail(self, filepath, async=False):
        """ Returns a thumbnail pixbuf for <filepath>, transparently handling
        both normal image files and archives. If a thumbnail file already exists,
        it is re-used. Otherwise, a new thumbnail is created from <filepath>.

        Returns None if thumbnail creation failed, or if the thumbnail creation
        is run asynchrounosly. """

        # Update width and height from preferences if they haven't been set explicitly
        if self.default_sizes:
            self.width = prefs['thumbnail size']
            self.height = prefs['thumbnail size']

        if self._thumbnail_exists(filepath):
            thumbpath = self._path_to_thumbpath(filepath)
            pixbuf = image_tools.load_pixbuf(thumbpath)
            self.thumbnail_finished(filepath, pixbuf)
            return pixbuf

        else:
            if async:
                thread = threading.Thread(target=self._create_thumbnail,
                                          args=(filepath, ))
                thread.name += '-thumbnailer'
                thread.setDaemon(True)
                thread.start()
                return None
            else:
                return self._create_thumbnail(filepath)
Exemplo n.º 18
0
class Thumbnailer(object):
    """ The Thumbnailer class is responsible for managing MComix
    internal thumbnail creation. Depending on its settings,
    it either stores thumbnails on disk and retrieves them later,
    or simply creates new thumbnails each time it is called. """

    def __init__(self, dst_dir=constants.THUMBNAIL_PATH):

        self.store_on_disk = prefs['create thumbnails']
        self.dst_dir = dst_dir
        self.width = prefs['thumbnail size']
        self.height = prefs['thumbnail size']
        self.default_sizes = True
        self.force_recreation = False

    def set_size(self, width, height):
        """ Sets <weight> and <height> for created thumbnails. """
        self.width = width
        self.height = height
        self.default_sizes = False

    def set_force_recreation(self, force_recreation):
        """ If <force_recreation> is True, thumbnails stored on disk
        will always be re-created instead of being re-used. """
        self.force_recreation = force_recreation

    def set_store_on_disk(self, store_on_disk):
        """ Changes the thumbnailer's behaviour to store files on
        disk, or just create new thumbnails each time it was called. """
        self.store_on_disk = store_on_disk

    def set_destination_dir(self, dst_dir):
        """ Changes the Thumbnailer's storage directory. """
        self.dst_dir = dst_dir

    def thumbnail(self, filepath, async=False):
        """ Returns a thumbnail pixbuf for <filepath>, transparently handling
        both normal image files and archives. If a thumbnail file already exists,
        it is re-used. Otherwise, a new thumbnail is created from <filepath>.

        Returns None if thumbnail creation failed, or if the thumbnail creation
        is run asynchrounosly. """

        # Update width and height from preferences if they haven't been set explicitly
        if self.default_sizes:
            self.width = prefs['thumbnail size']
            self.height = prefs['thumbnail size']

        thumbpath = self._path_to_thumbpath(filepath)
        if self._thumbnail_exists(filepath):
            pixbuf = image_tools.load_pixbuf(thumbpath)
            self.thumbnail_finished(filepath, pixbuf)
            return pixbuf

        else:
            if async:
                thread = threading.Thread(target=self._create_thumbnail, args=(filepath,))
                thread.setDaemon(True)
                thread.start()
                return None
            else:
                return self._create_thumbnail(filepath)