Add support for SVG images

This commit is contained in:
Hugo Posnic 2023-04-04 22:47:22 +02:00
parent 5fde80b40c
commit 0f7803a82c
12 changed files with 119 additions and 25 deletions

View File

@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.
## [1.7.0] - DEV
### Added
- 🌟 SVG support.
- New start screen with an AdwStatusPage.
- Add debug information in about window.

View File

@ -4,13 +4,13 @@
## Compress your images
Curtail (previously ImCompressor) is an useful image compressor, supporting PNG, JPEG and WebP file types.
Curtail (previously ImCompressor) is an useful image compressor, supporting PNG, JPEG, WebP and SVG file types.
It support both lossless and lossy compression modes with an option to whether keep or not metadata of images.
It is inspired by [Trimage](https://github.com/Kilian/Trimage) and [Image-Optimizer](https://github.com/GijsGoudzwaard/Image-Optimizer).
### Supported formats
PNG, JPEG, WebP
PNG, JPEG, WebP, SVG
## Screenshot

View File

@ -69,6 +69,7 @@
}
]
},
"python3-scour.json",
{
"name": "curtail",
"builddir": true,

View File

@ -8,7 +8,7 @@
<name translatable="no">Curtail</name>
<summary>Compress your images</summary>
<description>
<p>Optimize your images with Curtail, a useful image compressor that supports PNG, JPEG and WebP file types.</p>
<p>Optimize your images with Curtail, a useful image compressor that supports PNG, JPEG, WebP and SVG file types.</p>
<p>It supports both lossless and lossy compression modes with an option to whether keep or not metadata of images.</p>
</description>
<developer_name translatable="no">Hugo Posnic</developer_name>

View File

@ -53,8 +53,13 @@
</key>
<key type="b" name="jpg-progressive">
<default>false</default>
<summary>Enable progressive encoding for jpegs</summary>
<summary>Enable progressive encoding for JPEG images.</summary>
<description>Optionally encode jpeg images progressively.</description>
</key>
<key type="b" name="svg-maximum-level">
<default>false</default>
<summary>Enable maximum compression for SVG images.</summary>
<description>Optionally enable maximum cleaning of SVG images.</description>
</key>
<key type="i" name="compression-timeout">
<default>30</default>

View File

@ -64,7 +64,7 @@
</property>
<property name="valign">center</property>
</object>
</child>"
</child>
</object>
</child>
</object>
@ -199,6 +199,22 @@
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="no">SVG</property>
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">SVG Maximum Compression Level</property>
<property name="subtitle" translatable="yes">Can be more destructive for the image</property>
<child>
<object class="GtkSwitch" id="toggle_svg_maximum_level">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: curtail\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-03 17:17+0200\n"
"POT-Creation-Date: 2023-04-04 22:47+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -25,7 +25,7 @@ msgstr ""
#: data/com.github.huluti.Curtail.appdata.xml.in:11
msgid ""
"Optimize your images with Curtail, a useful image compressor that supports "
"PNG, JPEG and WebP file types."
"PNG, JPEG, WebP and SVG file types."
msgstr ""
#: data/com.github.huluti.Curtail.appdata.xml.in:12
@ -559,7 +559,7 @@ msgid "Lossless compression level to use for WebP images."
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:56
msgid "Enable progressive encoding for jpegs"
msgid "Enable progressive encoding for JPEG images."
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:57
@ -567,10 +567,18 @@ msgid "Optionally encode jpeg images progressively."
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:61
msgid "Compression Timeout"
msgid "Enable maximum compression for SVG images."
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:62
msgid "Optionally enable maximum cleaning of SVG images."
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:66
msgid "Compression Timeout"
msgstr ""
#: data/com.github.huluti.Curtail.gschema.xml:67
msgid "Compression timeout for each image."
msgstr ""
@ -631,6 +639,14 @@ msgstr ""
msgid "Progressive Encode JPG"
msgstr ""
#: data/ui/preferences.ui:207
msgid "SVG Maximum Compression Level"
msgstr ""
#: data/ui/preferences.ui:208
msgid "Can be more destructive for the image"
msgstr ""
#: data/ui/menu.ui:10
msgid "Keyboard Shortcuts"
msgstr ""
@ -667,11 +683,11 @@ msgstr ""
msgid "Main Menu"
msgstr ""
#: src/compressor.py:86
#: src/compressor.py:90
msgid "Compression has reached the configured timeout of {} seconds."
msgstr ""
#: src/compressor.py:90
#: src/compressor.py:94
msgid "An unknown error has occured"
msgstr ""
@ -679,20 +695,24 @@ msgstr ""
msgid "All images"
msgstr ""
#: src/tools.py:36
#: src/tools.py:37
msgid "PNG images"
msgstr ""
#: src/tools.py:40
#: src/tools.py:41
msgid "JPEG images"
msgstr ""
#: src/tools.py:44
#: src/tools.py:45
msgid "WebP images"
msgstr ""
#: src/tools.py:113 src/tools.py:121 src/tools.py:128 src/tools.py:135
#: src/tools.py:163
#: src/tools.py:49
msgid "SVG images"
msgstr ""
#: src/tools.py:121 src/tools.py:128 src/tools.py:135 src/tools.py:142
#: src/tools.py:149 src/tools.py:179
msgid "Version not found"
msgstr ""

14
python3-scour.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "python3-scour",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"scour\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/75/19/f519ef8aa2f379935a44212c5744e2b3a46173bf04e0110fb7f4af4028c9/scour-0.38.2.tar.gz",
"sha256": "6881ec26660c130c5ecd996ac6f6b03939dd574198f50773f2508b81a68e0daf"
}
]
}

View File

@ -49,11 +49,13 @@ class Compressor():
self.png_lossless_level = self._settings.get_int('png-lossless-level')
self.jpg_lossy_level = self._settings.get_int('jpg-lossy-level')
self.do_jpg_progressive = self._settings.get_boolean('jpg-progressive')
self.jpg_progressive = self._settings.get_boolean('jpg-progressive')
self.webp_lossless_level = self._settings.get_int('webp-lossless-level')
self.webp_lossy_level = self._settings.get_int('webp-lossy-level')
self.svg_maximum_level = self._settings.get_boolean('svg-maximum-level')
def compress_images(self):
self.thread = threading.Thread(target=self._compress_images)
self.thread.start()
@ -68,6 +70,8 @@ class Compressor():
command = self.build_jpg_command(result_item)
elif file_type == 'webp':
command = self.build_webp_command(result_item)
elif file_type == 'svg':
command = self.build_svg_command(result_item)
self.run_command(command, result_item) # compress image
GLib.idle_add(self.c_enable_compression, True)
@ -129,7 +133,7 @@ class Compressor():
jpegoptim = 'jpegoptim --max={} -o -f "{}"'
jpegoptim2 = 'jpegoptim -o -f "{}"'
if self.do_jpg_progressive:
if self.jpg_progressive:
jpegoptim += ' --all-progressive'
jpegoptim2 += ' --all-progressive'
@ -174,3 +178,13 @@ class Compressor():
return command
def build_svg_command(self, result_item):
command = 'scour -i {} -o {}'.format(result_item.filename,
result_item.new_filename)
if self.svg_maximum_level:
command += ' --enable-viewboxing --enable-id-stripping'
command += ' --enable-comment-stripping --shorten-ids --indent=none'
return command

View File

@ -37,6 +37,7 @@ class CurtailPrefsWindow(Adw.PreferencesWindow):
spin_jpg_lossy_level = Gtk.Template.Child()
spin_webp_lossy_level = Gtk.Template.Child()
toggle_jpg_progressive = Gtk.Template.Child()
toggle_svg_maximum_level = Gtk.Template.Child()
_settings = Gio.Settings.new(SETTINGS_SCHEMA)
@ -113,6 +114,11 @@ class CurtailPrefsWindow(Adw.PreferencesWindow):
self.toggle_jpg_progressive.connect('notify::active', self.on_bool_changed,
'jpg-progressive')
# Maxium SVG compression
self.toggle_svg_maximum_level.set_active(self._settings.get_boolean('svg-maximum-level'))
self.toggle_svg_maximum_level.connect('notify::active', self.on_bool_changed,
'svg-maximum-level')
def on_bool_changed(self, switch, state, key):
self._settings.set_boolean(key, switch.get_active())
# Additional actions

View File

@ -31,6 +31,7 @@ def add_filechooser_filters(dialog):
all_images.add_mime_type('image/jpeg')
all_images.add_mime_type('image/png')
all_images.add_mime_type('image/webp')
all_images.add_mime_type('image/svg+xml')
png_images = Gtk.FileFilter()
png_images.set_name(_("PNG images"))
@ -44,11 +45,16 @@ def add_filechooser_filters(dialog):
webp_images.set_name(_("WebP images"))
webp_images.add_mime_type('image/webp')
svg_images = Gtk.FileFilter()
svg_images.set_name(_("SVG images"))
svg_images.add_mime_type('image/svg+xml')
file_filters = Gio.ListStore.new(Gtk.FileFilter)
file_filters.append(all_images)
file_filters.append(png_images)
file_filters.append(jpeg_images)
file_filters.append(webp_images)
file_filters.append(svg_images)
dialog.set_filters(file_filters)
@ -62,6 +68,8 @@ def get_file_type(filename):
return 'png'
elif content_type == 'image/webp':
return 'webp'
elif content_type == 'image/svg+xml':
return 'svg'
else:
return None
else:
@ -109,42 +117,51 @@ def debug_infos():
try:
jpegoptim = subprocess.check_output(['jpegoptim', '--version'])
jpegoptim = extract_version(jpegoptim.decode('utf-8'))
except Exception as err:
except Exception:
jpegoptim = _('Version not found')
# Oxipng
try:
oxipng = subprocess.check_output(['oxipng', '--version'])
oxipng = extract_version(oxipng.decode('utf-8'))
except Exception as err:
except Exception:
oxipng = _('Version not found')
# pngquant
try:
pngquant = subprocess.check_output(['pngquant', '--version'])
pngquant = extract_version(pngquant.decode('utf-8'))
except Exception as err:
except Exception:
pngquant = _('Version not found')
# Libwebp
try:
libwebp = subprocess.check_output(['cwebp', '-version'])
libwebp = extract_version(libwebp.decode('utf-8'))
except Exception as err:
except Exception:
libwebp = _('Version not found')
# Scour
try:
scour = subprocess.check_output(['scour', '--version'])
scour = extract_version(scour.decode('utf-8'))
except Exception:
scour = _('Version not found')
debug = '''Python: {}\n
Gtk: {}\n
Jpegoptim: {}\n
Oxipng: {}\n
pngquant: {}\n
Libwebp: {}\n'''.format(
Libwebp: {}\n
Scour: {}\n'''.format(
python_version,
gtk_version,
jpegoptim,
oxipng,
pngquant,
libwebp
libwebp,
scour
)
return debug

View File

@ -226,7 +226,7 @@ class CurtailWindow(Gtk.ApplicationWindow):
def check_extension(self, filename):
file_type = get_file_type(filename)
if file_type:
return file_type in ('png', 'jpg', 'webp')
return file_type in ('png', 'jpg', 'webp', 'svg')
else:
return False