diff --git a/README.md b/README.md index d82d12b..5af5220 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ metadata. - `python3-mutagen` for audio support - `python3-gi-cairo` and `gir1.2-poppler-0.18` for PDF support - `gir1.2-gdkpixbuf-2.0` for images support +- `gir1.2-rsvg-2.0` for svg support - `FFmpeg`, optionally, for video support - `libimage-exiftool-perl` for everything else - `bubblewrap`, optionally, for sandboxing diff --git a/libmat2/images.py b/libmat2/images.py index 32a329f..8bef3f8 100644 --- a/libmat2/images.py +++ b/libmat2/images.py @@ -1,18 +1,48 @@ import imghdr import os -from typing import Set +from typing import Set, Dict, Union import cairo import gi gi.require_version('GdkPixbuf', '2.0') -from gi.repository import GdkPixbuf, GLib +gi.require_version('Rsvg', '2.0') +from gi.repository import GdkPixbuf, GLib, Rsvg from . import exiftool # Make pyflakes happy assert Set +class SVGParser(exiftool.ExiftoolParser): + mimetypes = {'image/svg+xml', } + meta_allowlist = {'Directory', 'ExifToolVersion', 'FileAccessDate', + 'FileInodeChangeDate', 'FileModifyDate', 'FileName', + 'FilePermissions', 'FileSize', 'FileType', + 'FileTypeExtension', 'ImageHeight', 'ImageWidth', + 'MIMEType', 'SVGVersion', 'SourceFile', 'ViewBox' + } + + def remove_all(self) -> bool: + svg = Rsvg.Handle.new_from_file(self.filename) + dimensions = svg.get_dimensions() + surface = cairo.SVGSurface(self.output_filename, + dimensions.height, + dimensions.width) + context = cairo.Context(surface) + svg.render_cairo(context) + surface.finish() + return True + + def get_meta(self) -> Dict[str, Union[str, dict]]: + meta = super().get_meta() + + # The namespace is mandatory, but thereis only one bossible. + ns = 'http://www.w3.org/2000/svg' + if meta.get('Xmlns', ns) == ns: + meta.pop('Xmlns') + return meta + class PNGParser(exiftool.ExiftoolParser): mimetypes = {'image/png', } meta_allowlist = {'SourceFile', 'ExifToolVersion', 'FileName', diff --git a/tests/data/dirty.svg b/tests/data/dirty.svg new file mode 100644 index 0000000..e2bde85 --- /dev/null +++ b/tests/data/dirty.svg @@ -0,0 +1,636 @@ + + + + + + Adwaita Icon Template + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + GNOME Design Team + + + mat2's source code + + Adwaita Icon Template + + + mat2 + logo + metadata + + + 2019 07 13 + + + LGPL + + + + + jvoisin + + + mat2-testdata-svg + + English + + This is a test svg image for mat2's testsuite + + + jvoisin, and Rose for the design + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/embedded.docx b/tests/data/embedded.docx index b134724..615e522 100644 Binary files a/tests/data/embedded.docx and b/tests/data/embedded.docx differ diff --git a/tests/data/embedded.odt b/tests/data/embedded.odt index 62bf8cc..c5fffc8 100644 Binary files a/tests/data/embedded.odt and b/tests/data/embedded.odt differ diff --git a/tests/test_libmat2.py b/tests/test_libmat2.py index 64e679f..796d2f1 100644 --- a/tests/test_libmat2.py +++ b/tests/test_libmat2.py @@ -73,13 +73,13 @@ class TestParameterInjection(unittest.TestCase): class TestUnsupportedEmbeddedFiles(unittest.TestCase): - def test_odt_with_svg(self): + def test_odt_with_py(self): shutil.copy('./tests/data/embedded.odt', './tests/data/clean.odt') p = office.LibreOfficeParser('./tests/data/clean.odt') self.assertFalse(p.remove_all()) os.remove('./tests/data/clean.odt') - def test_docx_with_svg(self): + def test_docx_with_py(self): shutil.copy('./tests/data/embedded.docx', './tests/data/clean.docx') p = office.MSOfficeParser('./tests/data/clean.docx') self.assertFalse(p.remove_all()) @@ -862,3 +862,27 @@ class TestCleaning(unittest.TestCase): os.remove('./tests/data/dirty.tar.xz') os.remove('./tests/data/dirty.cleaned.tar.xz') os.remove('./tests/data/dirty.cleaned.cleaned.tar.xz') + + def test_svg(self): + shutil.copy('./tests/data/dirty.svg', './tests/data/clean.svg') + p = images.SVGParser('./tests/data/clean.svg') + + meta = p.get_meta() + self.assertEqual(meta['WorkCreatorAgentTitle'], 'GNOME Design Team') + self.assertEqual(meta['WorkSubject'], ['mat2', 'logo', 'metadata']) + self.assertEqual(meta['ID'], 'svg11300') + self.assertEqual(meta['Output_extension'], + 'org.inkscape.output.svg.inkscape') + + ret = p.remove_all() + self.assertTrue(ret) + + p = images.SVGParser('./tests/data/clean.cleaned.svg') + self.assertEqual(p.get_meta(), {}) + self.assertTrue(p.remove_all()) + + os.remove('./tests/data/clean.svg') + os.remove('./tests/data/clean.cleaned.svg') + os.remove('./tests/data/clean.cleaned.cleaned.svg') + +