diff sat/core/sat_main.py @ 3259:f300d78f08f3

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
author Goffi <goffi@goffi.org>
date Sun, 19 Apr 2020 16:53:44 +0200
parents 6cf4bd6972c2
children 4240b44842bb
line wrap: on
line diff
--- a/sat/core/sat_main.py	Sun Apr 19 16:40:34 2020 +0200
+++ b/sat/core/sat_main.py	Sun Apr 19 16:53:44 2020 +0200
@@ -174,6 +174,7 @@
         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 @@
 
         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):