#!/usr/bin/python3
+import PIL
+import io
import logging
import os.path
import re
+import urllib.parse
from . import misc
from . import util
mimetype, blob_id, size) VALUES(%s, %s, %s, %s, %s, %s, %s) RETURNING *", path,
filename, author.uid, address, mimetype, blob.id, len(data))
+ def find_image(self, path, filename):
+ for p in (path, os.path.dirname(path)):
+ file = self.get_file_by_path(os.path.join(p, filename))
+
+ if file and file.is_image():
+ return file
+
class Page(misc.Object):
def init(self, id, data=None):
def _render(self, text):
logging.debug("Rendering %s" % self)
+ # Link images
+ replacements = []
+ for match in re.finditer(r"!\[(.*)\]\((.*)\)", text):
+ alt_text, url = match.groups()
+
+ # Skip any absolute and external URLs
+ if url.startswith("/") or url.startswith("https://") or url.startswith("http://"):
+ continue
+
+ # Try to split query string
+ url, delimiter, qs = url.partition("?")
+
+ # Parse query arguments
+ args = urllib.parse.parse_qs(qs)
+
+ # Find image
+ file = self.backend.wiki.find_image(self.page, url)
+ if not file:
+ continue
+
+ # Scale down the image if not already done
+ if not "s" in args:
+ args["s"] = "768"
+
+ # Format URL
+ url = "%s?%s" % (file.url, urllib.parse.urlencode(args))
+
+ replacements.append((match.span(), file, alt_text, url))
+
+ # Apply all replacements
+ for (start, end), file, alt_text, url in reversed(replacements):
+ text = text[:start] + "[![%s](%s)](%s?action=detail)" % (alt_text, url, file.url) + text[end:]
+
+ # Add wiki links
patterns = (
(r"\[\[([\w\d\/]+)(?:\|([\w\d\s]+))\]\]", r"/\1", r"\2", None, None),
(r"\[\[([\w\d\/\-]+)\]\]", r"/\1", r"\1", self.backend.wiki.get_page_title, r"\1"),
def size(self):
return self.data.size
+ @lazy_property
+ def author(self):
+ if self.data.author_uid:
+ return self.backend.accounts.get_by_uid(self.data.author_uid)
+
+ @property
+ def created_at(self):
+ return self.data.created_at
+
+ def is_pdf(self):
+ return self.mimetype in ("application/pdf", "application/x-pdf")
+
def is_image(self):
return self.mimetype.startswith("image/")
if res:
return bytes(res.data)
+
+ def get_thumbnail(self, size):
+ image = PIL.Image.open(io.BytesIO(self.blob))
+
+ # Resize the image to the desired resolution
+ image.thumbnail((size, size), PIL.Image.ANTIALIAS)
+
+ with io.BytesIO() as f:
+ # If writing out the image does not work with optimization,
+ # we try to write it out without any optimization.
+ try:
+ image.save(f, image.format, optimize=True, quality=98)
+ except:
+ image.save(f, image.format, quality=98)
+
+ return f.getvalue()