core: image convertion + SVG support:

/!\ new optional dependency: CairoSVG (with installed `[SVG]` extra)

- new `convert` method in `tools.image` to save an image in an other format, with support
  for SVG (when CairoSVG is available)
- new `imageConvert` method is available for frontends
This commit is contained in:
Goffi 2020-04-19 16:53:44 +02:00
commit 47ec15cc46

View file

@ -174,6 +174,7 @@ class SAT(service.Service):
self.bridge.register_method("imageCheck", self._imageCheck)
self.bridge.register_method("imageResize", self._imageResize)
self.bridge.register_method("imageGeneratePreview", self._imageGeneratePreview)
self.bridge.register_method("imageConvert", self._imageConvert)
self.memory.initialized.addCallback(lambda __: defer.ensureDeferred(self._postMemoryInit()))
@ -796,6 +797,63 @@ class SAT(service.Service):
return preview_path
def _imageConvert(self, source, dest, extra, profile_key):
client = self.getClient(profile_key) if profile_key else None
source = Path(source)
dest = None if not dest else Path(dest)
extra = data_format.deserialise(extra)
d = defer.ensureDeferred(self.imageConvert(client, source, dest, extra))
d.addCallback(lambda dest_path: str(dest_path))
return d
async def imageConvert(self, client, source, dest=None, extra=None):
"""Helper method to convert an image from one format to an other
@param client(SatClient, None): client to use for caching
this parameter is only used if dest is None
if client is None, common cache will be used insted of profile cache
@param source(Path): path to the image to convert
@param dest(None, Path, file): where to save the converted file
- None: use a cache file (uid generated from hash of source)
file will be converted to PNG
- Path: path to the file to create/overwrite
- file: a file object which must be opened for writing in binary mode
@param extra(dict, None): conversion options
see [image.convert] for details
@return (Path): path to the converted image
@raise ValueError: an issue happened with source of dest
"""
if not source.is_file:
raise ValueError(f"Source file {source} doesn't exist!")
if dest is None:
# we use hash as id, to re-use potentially existing conversion
path_hash = hashlib.sha256(str(source).encode()).hexdigest()
uid = f"{source.stem}_{path_hash}_convert_png"
filename = f"{uid}.png"
if client is None:
cache = self.common_cache
else:
cache = client.cache
metadata = cache.getMetadata(uid=uid)
if metadata is not None:
# there is already a conversion for this image in cache
return metadata['path']
else:
with cache.cacheData(
source='HOST_IMAGE_CONVERT',
uid=uid,
filename=filename) as cache_f:
converted_path = await image.convert(
source,
dest=cache_f,
extra=extra
)
return converted_path
else:
return await image.convert(source, dest, extra)
# local dirs
def getLocalPath(self, client, dir_name, *extra_path, **kwargs):