Fix SVG uploads, fix entire Upload model deleted

This commit is contained in:
miruka 2019-11-06 07:50:31 -04:00
parent ace79a169c
commit 4c15b7dc62
4 changed files with 41 additions and 8 deletions

View File

@ -1,5 +1,4 @@
- Media - Media
- SVG uploads
- Uploading progress bar (+local echo) - Uploading progress bar (+local echo)
- Text bubbles theming - Text bubbles theming
- Directly create cache files for our uploads before actually uploading - Directly create cache files for our uploads before actually uploading

View File

@ -1,6 +1,7 @@
hsluv == 0.0.2 hsluv == 0.0.2
Pillow >= 5.4.1, < 6 Pillow >= 5.4.1, < 6
pymediainfo >= 4.1, < 5 pymediainfo >= 4.1, < 5
cairosvg >= 2.4.2, < 3
aiofiles >= 0.4.0, < 0.5 aiofiles >= 0.4.0, < 0.5
appdirs >= 1.4.3, < 2 appdirs >= 1.4.3, < 2
filetype >= 1.0.5, < 2 filetype >= 1.0.5, < 2

View File

@ -18,6 +18,7 @@ from typing import (
) )
from uuid import uuid4 from uuid import uuid4
import cairosvg
from PIL import Image as PILImage from PIL import Image as PILImage
from pymediainfo import MediaInfo from pymediainfo import MediaInfo
@ -252,18 +253,22 @@ class MatrixClient(nio.AsyncClient):
content["url"] = url content["url"] = url
if kind == "image": if kind == "image":
is_svg = mime == "image/svg+xml"
event_type = \ event_type = \
nio.RoomEncryptedImage if encrypt else nio.RoomMessageImage nio.RoomEncryptedImage if encrypt else nio.RoomMessageImage
content["msgtype"] = "m.image" content["msgtype"] = "m.image"
content["info"]["w"], content["info"]["h"] = \ content["info"]["w"], content["info"]["h"] = (
utils.svg_dimensions(str(path)) if is_svg else
PILImage.open(path).size PILImage.open(path).size
)
try: try:
thumb_url, thumb_info, thumb_crypt_dict = \ thumb_url, thumb_info, thumb_crypt_dict = \
await self.upload_thumbnail( await self.upload_thumbnail(
path, upload_item, encrypt=encrypt, path, upload_item, is_svg=is_svg, encrypt=encrypt,
) )
except (UneededThumbnail, UnthumbnailableError): except (UneededThumbnail, UnthumbnailableError):
pass pass
@ -313,7 +318,7 @@ class MatrixClient(nio.AsyncClient):
content["filename"] = path.name content["filename"] = path.name
upload_item.status = UploadStatus.Success upload_item.status = UploadStatus.Success
del self.models[Upload, room_id] del self.models[Upload, room_id][upload_item.uuid]
uuid = str(uuid4()) uuid = str(uuid4())
@ -451,19 +456,31 @@ class MatrixClient(nio.AsyncClient):
self, self,
path: Union[Path, str], path: Union[Path, str],
item: Optional[Upload] = None, item: Optional[Upload] = None,
is_svg: bool = False,
encrypt: bool = False, encrypt: bool = False,
) -> Tuple[str, Dict[str, Any], CryptDict]: ) -> Tuple[str, Dict[str, Any], CryptDict]:
png_modes = ("1", "L", "P", "RGBA") png_modes = ("1", "L", "P", "RGBA")
try: try:
thumb = PILImage.open(path) if is_svg:
svg_width, svg_height = utils.svg_dimensions(str(path))
thumb = PILImage.open(io.BytesIO(
cairosvg.svg2png(
url = str(path),
parent_width = svg_width,
parent_height = svg_height,
),
))
else:
thumb = PILImage.open(path)
small = thumb.width <= 800 and thumb.height <= 600 small = thumb.width <= 800 and thumb.height <= 600
is_jpg_png = thumb.format in ("JPEG", "PNG") is_jpg_png = thumb.format in ("JPEG", "PNG")
jpgable_png = thumb.format == "PNG" and thumb.mode not in png_modes jpgable_png = thumb.format == "PNG" and thumb.mode not in png_modes
if small and is_jpg_png and not jpgable_png: if small and is_jpg_png and not jpgable_png and not is_svg:
raise UneededThumbnail() raise UneededThumbnail()
if item: if item:

View File

@ -3,7 +3,7 @@ import html
import xml.etree.cElementTree as xml_etree # FIXME: bandit warning import xml.etree.cElementTree as xml_etree # FIXME: bandit warning
from enum import Enum from enum import Enum
from enum import auto as autostr from enum import auto as autostr
from typing import IO, Optional from typing import IO, Tuple, Union
import filetype import filetype
@ -26,7 +26,7 @@ def dict_update_recursive(dict1, dict2):
dict1[k] = dict2[k] dict1[k] = dict2[k]
def is_svg(file: IO) -> bool: def is_svg(file: Union[IO, bytes, str]) -> bool:
try: try:
_, element = next(xml_etree.iterparse(file, ("start",))) _, element = next(xml_etree.iterparse(file, ("start",)))
return element.tag == "{http://www.w3.org/2000/svg}svg" return element.tag == "{http://www.w3.org/2000/svg}svg"
@ -34,6 +34,22 @@ def is_svg(file: IO) -> bool:
return False return False
def svg_dimensions(file: Union[IO, bytes, str]) -> Tuple[int, int]:
attrs = xml_etree.parse(file).getroot().attrib
try:
width = round(float(attrs.get("width", attrs["viewBox"].split()[3])))
except (KeyError, IndexError, ValueError, TypeError):
width = 256
try:
height = round(float(attrs.get("height", attrs["viewBox"].split()[4])))
except (KeyError, IndexError, ValueError, TypeError):
height = 256
return (width, height)
def guess_mime(file: IO) -> str: def guess_mime(file: IO) -> str:
if is_svg(file): if is_svg(file):
return "image/svg+xml" return "image/svg+xml"