Update attributes after Sphinx cache is updated.

        :param dict album_cache: Cache of Imgur albums to read. Keys are Imgur IDs, values are Album instances.
        :param dict image_cache: Cache of Imgur images to read. Keys are Imgur IDs, values are Image instances.
        :param function warn_node: sphinx.environment.BuildEnvironment.warn_node without needing node argument.

def finalize(self, album_cache, image_cache, warn_node):
        """Update attributes after Sphinx cache is updated.

        :param dict album_cache: Cache of Imgur albums to read. Keys are Imgur IDs, values are Album instances.
        :param dict image_cache: Cache of Imgur images to read. Keys are Imgur IDs, values are Image instances.
        :param function warn_node: sphinx.environment.BuildEnvironment.warn_node without needing node argument.
        """
        album = album_cache[self.imgur_id] if self.album else None
        image = image_cache[album.cover_id] if self.album else image_cache[self.imgur_id]
        options = self.options

        # Determine target. Code in directives.py handles defaults and unsets target_* if :target: is set.
        if options['target_gallery'] and (album.in_gallery if album else image.in_gallery):
            options['target'] = '//imgur.com/gallery/{}'.format(album.imgur_id if album else image.imgur_id)
        elif options['target_page']:
            options['target'] = '//imgur.com/{}'.format(album.imgur_id if album else image.imgur_id)
        elif options['target_largest'] and not album:
            options['target'] = '//i.imgur.com/' + image.filename(full_size=True)
        elif not options['target'] and (options['width'] or options['height'] or options['scale']):
            options['target'] = '//i.imgur.com/' + image.filename(full_size=True)

        # Handle scale with no API data.
        if options['scale']:
            if not image.width and not options['width'] and not image.height and not options['height']:
                options['scale'] = ''
                warn_node('Could not obtain image size. :scale: option is ignored.')
            elif not image.width and not options['width']:
                warn_node('Could not obtain image width. :scale: option is partially ignored.')
            elif not image.width or not image.height:
                warn_node('Could not obtain image height. :scale: option is partially ignored.')

        # Handle scale, width, and height.
        if options['scale'] and (options['width'] or image.width):
            match = RE_WIDTH_HEIGHT.match(options['width'] or '%dpx' % image.width)
            options['width'] = '{}{}'.format(int(float(match.group(1)) * (options['scale'] / 100.0)), match.group(2))
        if options['scale'] and (options['height'] or image.height):
            match = RE_WIDTH_HEIGHT.match(options['height'] or '%dpx' % image.height)
            options['height'] = '{}{}'.format(int(float(match.group(1)) * (options['scale'] / 100.0)), match.group(2))

        # Set src and style.
        self.src = '//i.imgur.com/' + image.filename(options['width'], options['height'])
        style = [p for p in ((k, options[k]) for k in ('width', 'height')) if p[1]]
        if style:
            self.style = '; '.join('{}: {}'.format(k, v) for k, v in style)

        # Determine alt text.
        if not options['alt']:
            options['alt'] = image.title or self.src[2:]