import os
import posixpath
from docutils.parsers.rst.directives import class_option, nonnegative_int
from docutils.parsers.rst.directives.images import Figure
from sphinx.addnodes import download_reference
from sphinx.writers.html import HTMLTranslator
from PIL import Image
THUMBNAILS_FOLDER_NAME = '_thumbnails'
class FancyFigure(Figure):
option_spec = Figure.option_spec.copy()
option_spec.update({
'rel': class_option,
'fitwidth': nonnegative_int,
'fitheight': nonnegative_int,
})
has_content = True
def run(self):
dimensions = (self.options.pop('fitwidth', None), self.options.pop('fitheight', None))
if not all(dimensions):
dimensions = (200, 200)
rel_path = os.path.split(self.arguments[0])
#self.options['target'] = self.arguments[0]
source_root = os.path.split(self.state.document.attributes['source'])[0]
real_path = os.path.join(source_root, *rel_path)
tn_dir = os.path.join(source_root, THUMBNAILS_FOLDER_NAME)
thumb_path = os.path.join(tn_dir, 'tn_' + rel_path[1])
if not os.path.isdir(tn_dir):
if os.path.exists(tn_dir):
raise Exception('%s must be a directory' % THUMBNAILS_FOLDER_NAME)
os.mkdir(tn_dir)
if not os.path.exists(real_path):
return super(FancyFigure, self).run()
def set_size(size):
for k, v in zip(['width', 'height'], size):
self.options[k] = str(v)
def make_thumb():
thumb = Image.open(real_path)
thumb.thumbnail(dimensions, Image.ANTIALIAS)
set_size(thumb.size)
thumb.save(thumb_path)
if not os.path.exists(thumb_path) or os.path.getmtime(thumb_path) < os.path.getmtime(real_path):
make_thumb()
elif os.path.exists(thumb_path):
thumb = Image.open(thumb_path)
compare = any(i == j for i, j in zip(dimensions, thumb.size))
if not compare:
make_thumb()
else:
set_size(thumb.size)
download = download_reference(reftarget=self.arguments[0], rel=' '.join(self.options['rel']))
self.arguments[0] = os.path.relpath(thumb_path, source_root)
download += super(FancyFigure, self).run()
return [download]
def visit_download_reference(self, node):
rel = 'rel="%s"' % node['rel'] if node.get('rel', None) else ''
if node.hasattr('filename'):
self.body.append(
'<a class="reference download internal" href="%s" %s>' %
(posixpath.join(self.builder.dlpath, node['filename']), rel))
self.context.append('</a>')
else:
self.context.append('')
def setup(app):
app.add_node(download_reference, html=(visit_download_reference, HTMLTranslator.depart_download_reference))
app.add_config_value('thumbnails_folder', THUMBNAILS_FOLDER_NAME, 'env')
app.add_config_value('thumbnails_size', (200, 200), 'env')
app.add_directive('fancyimage', FancyFigure)