mirror of
https://github.com/Huluti/Curtail.git
synced 2024-09-11 06:05:33 +03:00
Webp support (#80)
* Add basic webp support Co-authored-by: Hugo Posnic <hugo.posnic@protonmail.com>
This commit is contained in:
parent
21fe25205b
commit
cbd3acaf92
@ -2,13 +2,13 @@
|
||||
|
||||
## Compress your images
|
||||
|
||||
Curtail (previously ImCompressor) is an useful image compressor, supporting PNG and JPEG file types.
|
||||
Curtail (previously ImCompressor) is an useful image compressor, supporting PNG, JPEG and WEBP 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
|
||||
PNG, JPEG, WEBP
|
||||
|
||||
## Screenshot
|
||||
|
||||
@ -56,6 +56,7 @@ Curtail uses a number of open source projects to work properly:
|
||||
- [OptiPNG](http://optipng.sourceforge.net)
|
||||
- [pngquant](https://pngquant.org)
|
||||
- [Jpegoptim](https://github.com/tjko/jpegoptim)
|
||||
- [libwebp](https://storage.googleapis.com/downloads.webmproject.org/releases/webp/index.html)
|
||||
|
||||
## Donations
|
||||
|
||||
|
@ -44,6 +44,16 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libwebp",
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.2.0.tar.gz",
|
||||
"sha256": "2fc8bbde9f97f2ab403c0224fb9ca62b2e6852cbc519e91ceaa7c153ffd88a0c"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "curtail",
|
||||
"builddir": true,
|
||||
|
@ -7,7 +7,7 @@
|
||||
<name>Curtail</name>
|
||||
<summary>Compress your images</summary>
|
||||
<description>
|
||||
<p>Curtail is an useful image compressor, supporting PNG and JPEG file types.</p>
|
||||
<p>Curtail is an useful image compressor, supporting PNG, JPEG and WEBP file types.</p>
|
||||
<p>It support both lossless and lossy compression modes with an option to whether keep or not metadata of images.</p>
|
||||
</description>
|
||||
|
||||
|
@ -30,11 +30,21 @@
|
||||
<default>2</default>
|
||||
<summary>PNG Lossless Compression Level</summary>
|
||||
<description>Lossless compression level to use for PNG images.</description>
|
||||
</key>
|
||||
<key type="i" name="webp-lossless-level">
|
||||
<default>4</default>
|
||||
<summary>WEBP Lossless Compression Level</summary>
|
||||
<description>Lossless compression level to use for WEBP images.</description>
|
||||
</key>
|
||||
<key type="i" name="jpg-lossy-level">
|
||||
<default>90</default>
|
||||
<summary>JPG Lossy Compression Level</summary>
|
||||
<description>Lossy compression level to use for JPG images.</description>
|
||||
</key>
|
||||
<key type="i" name="webp-lossy-level">
|
||||
<default>70</default>
|
||||
<summary>WEBP Lossy Compression Level</summary>
|
||||
<description>Lossy compression level to use for WEBP images.</description>
|
||||
</key>
|
||||
<key type="b" name="jpg-progressive">
|
||||
<default>false</default>
|
||||
|
3
debian/control
vendored
3
debian/control
vendored
@ -22,7 +22,8 @@ Depends: ${misc:Depends},
|
||||
python3,
|
||||
optipng,
|
||||
pngquant,
|
||||
jpegoptim
|
||||
jpegoptim,
|
||||
webp
|
||||
Description: Compress your images
|
||||
Curtail (previously ImCompressor) is an useful image compressor, supporting PNG and JPEG file types.
|
||||
It support both lossless and lossy compression modes with an option to whether keep or not metadata of images.
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: curtail\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-03-12 19:14+0100\n"
|
||||
"POT-Creation-Date: 2021-06-16 18:12+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"
|
||||
@ -24,13 +24,14 @@ msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.desktop.in:5
|
||||
#: data/com.github.huluti.Curtail.appdata.xml.in:8 src/ui/window.ui:213
|
||||
#: src/window.py:308
|
||||
#: src/window.py:309
|
||||
msgid "Compress your images"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.appdata.xml.in:10
|
||||
msgid ""
|
||||
"Curtail is an useful image compressor, supporting PNG and JPEG file types."
|
||||
"Curtail is an useful image compressor, supporting PNG, JPEG and WEBP file "
|
||||
"types."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.appdata.xml.in:11
|
||||
@ -308,7 +309,7 @@ msgstr ""
|
||||
msgid "Save the compressed image into a new file."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:11 src/ui/preferences.ui:125
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:11 src/ui/preferences.ui:135
|
||||
msgid "Keep metadata"
|
||||
msgstr ""
|
||||
|
||||
@ -324,7 +325,7 @@ msgstr ""
|
||||
msgid "Use lossy mode to compress images."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:21 src/ui/preferences.ui:75
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:21 src/ui/preferences.ui:85
|
||||
msgid "Suffix to append at end of new file"
|
||||
msgstr ""
|
||||
|
||||
@ -332,7 +333,7 @@ msgstr ""
|
||||
msgid "Suffix to append at end of new file."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:26 src/ui/preferences.ui:167
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:26 src/ui/preferences.ui:177
|
||||
msgid "PNG Lossy Compression Level"
|
||||
msgstr ""
|
||||
|
||||
@ -348,27 +349,43 @@ msgstr ""
|
||||
msgid "Lossless compression level to use for PNG images."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:36 src/ui/preferences.ui:194
|
||||
msgid "JPG Lossy Compression Level"
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:36
|
||||
msgid "WEBP Lossless Compression Level"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:37
|
||||
msgid "Lossy compression level to use for JPG images."
|
||||
msgid "Lossless compression level to use for WEBP images."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:41
|
||||
msgid "Enable progressive encoding for jpegs"
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:41 src/ui/preferences.ui:204
|
||||
msgid "JPG Lossy Compression Level"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:42
|
||||
msgid "Optionally encode jpeg images progressively."
|
||||
msgid "Lossy compression level to use for JPG images."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:46 src/ui/preferences.ui:49
|
||||
msgid "Enable dark theme"
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:46 src/ui/preferences.ui:217
|
||||
msgid "WEBP Lossy Compression Level"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:47
|
||||
msgid "Lossy compression level to use for WEBP images."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:51
|
||||
msgid "Enable progressive encoding for jpegs"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:52
|
||||
msgid "Optionally encode jpeg images progressively."
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:56 src/ui/preferences.ui:59
|
||||
msgid "Enable dark theme"
|
||||
msgstr ""
|
||||
|
||||
#: data/com.github.huluti.Curtail.gschema.xml:57
|
||||
msgid "Use dark theme for the windows."
|
||||
msgstr ""
|
||||
|
||||
@ -380,7 +397,7 @@ msgstr ""
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/window.ui:75 src/window.py:168
|
||||
#: src/ui/window.ui:75 src/window.py:169
|
||||
msgid "Browse your files"
|
||||
msgstr ""
|
||||
|
||||
@ -392,33 +409,39 @@ msgstr ""
|
||||
msgid "Lossy"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:22 src/ui/menu.ui:6
|
||||
#: src/ui/preferences.ui:32 src/ui/menu.ui:6
|
||||
msgid "Preferences"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:99
|
||||
#: src/ui/preferences.ui:109
|
||||
msgid "Save the compressed image into a new file"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:148
|
||||
#: src/ui/preferences.ui:158
|
||||
msgid "General"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:218
|
||||
#: src/ui/preferences.ui:255
|
||||
msgid "Compression"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:250
|
||||
#: src/ui/preferences.ui:288
|
||||
msgid ""
|
||||
"PNG Lossless Compression Level\n"
|
||||
"(the higher it is, the slower it is)"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:264
|
||||
#: src/ui/preferences.ui:315
|
||||
msgid ""
|
||||
"WEBP Lossless Compression Level\n"
|
||||
"(the higher it is, the slower it is)"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:329
|
||||
msgid "Progressive Encode JPG"
|
||||
msgstr ""
|
||||
|
||||
#: src/ui/preferences.ui:287
|
||||
#: src/ui/preferences.ui:352
|
||||
msgid "Advanced"
|
||||
msgstr ""
|
||||
|
||||
@ -426,27 +449,27 @@ msgstr ""
|
||||
msgid "About Curtail"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:88
|
||||
#: src/window.py:89
|
||||
msgid "Filename"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:89
|
||||
#: src/window.py:90
|
||||
msgid "Old Size"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:90
|
||||
#: src/window.py:91
|
||||
msgid "New Size"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:91
|
||||
#: src/window.py:92
|
||||
msgid "Savings"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:155
|
||||
#: src/window.py:156
|
||||
msgid "Images are saved with <b>'{}' suffix</b>."
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:158
|
||||
#: src/window.py:159
|
||||
msgid "Images are <b>overwritten</b>."
|
||||
msgstr ""
|
||||
|
||||
@ -458,27 +481,27 @@ msgstr ""
|
||||
msgid "The file {} already exists. Do you want to compress the image anyway?"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:242
|
||||
#: src/window.py:243
|
||||
msgid "Format not supported"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:243
|
||||
#: src/window.py:244
|
||||
msgid "The format of {} is not supported."
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:247
|
||||
#: src/window.py:248
|
||||
msgid "Path not valid"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:248
|
||||
#: src/window.py:249
|
||||
msgid "{} doesn't exist."
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:307
|
||||
#: src/window.py:308
|
||||
msgid "translator-credits"
|
||||
msgstr ""
|
||||
|
||||
#: src/window.py:309
|
||||
#: src/window.py:310
|
||||
msgid "Distributed under the GNU GPL(v3) license.\n"
|
||||
msgstr ""
|
||||
|
||||
@ -490,10 +513,14 @@ msgstr ""
|
||||
msgid "All images"
|
||||
msgstr ""
|
||||
|
||||
#: src/tools.py:52
|
||||
#: src/tools.py:53
|
||||
msgid "PNG images"
|
||||
msgstr ""
|
||||
|
||||
#: src/tools.py:56
|
||||
#: src/tools.py:57
|
||||
msgid "JPEG images"
|
||||
msgstr ""
|
||||
|
||||
#: src/tools.py:61
|
||||
msgid "WEBP images"
|
||||
msgstr ""
|
||||
|
@ -71,6 +71,8 @@ class Compressor():
|
||||
command = self.build_png_command(lossy, metadata)
|
||||
elif file_type == 'jpg':
|
||||
command = self.build_jpg_command(lossy, metadata)
|
||||
elif file_type == 'webp':
|
||||
command = self.build_webp_command(lossy, metadata)
|
||||
self.run_command(command) # compress image
|
||||
|
||||
def command_finished(self, stdout, condition):
|
||||
@ -139,5 +141,27 @@ class Compressor():
|
||||
command = jpegoptim2.format(self.filename)
|
||||
return command
|
||||
|
||||
def build_webp_command(self, lossy, metadata):
|
||||
command = "cwebp " + self.filename
|
||||
|
||||
# cwebp doesn't preserve any metadata by default
|
||||
if metadata:
|
||||
command += " -metadata all"
|
||||
|
||||
if lossy:
|
||||
quality = self._settings.get_int('webp-lossy-level')
|
||||
else:
|
||||
command += " -lossless"
|
||||
quality = 100 # maximum cpu power for lossless
|
||||
|
||||
compression_level = self._settings.get_int('webp-lossless-level')
|
||||
|
||||
# multithreaded, (lossless) compression mode, quality, output
|
||||
command += " -mt -m {}".format(compression_level)
|
||||
command += " -q {}".format(quality)
|
||||
command += " -o {}".format(self.new_filename)
|
||||
|
||||
return command
|
||||
|
||||
def feed(self, stdout, condition):
|
||||
return True
|
||||
|
@ -34,7 +34,9 @@ class CurtailPrefsWindow(Gtk.Window):
|
||||
entry_suffix = Gtk.Template.Child()
|
||||
spin_png_lossy_level = Gtk.Template.Child()
|
||||
spin_png_lossless_level = Gtk.Template.Child()
|
||||
spin_webp_lossless_level = Gtk.Template.Child()
|
||||
spin_jpg_lossy_level = Gtk.Template.Child()
|
||||
spin_webp_lossy_level = Gtk.Template.Child()
|
||||
toggle_jpg_progressive = Gtk.Template.Child()
|
||||
toggle_dark_theme = Gtk.Template.Child()
|
||||
|
||||
@ -77,12 +79,24 @@ class CurtailPrefsWindow(Gtk.Window):
|
||||
self.spin_png_lossless_level.connect('value-changed',
|
||||
self.on_int_changed, 'png-lossless-level')
|
||||
|
||||
# WEBP Lossless Compression Level
|
||||
self.spin_webp_lossless_level.set_value(
|
||||
self._settings.get_int('webp-lossless-level'))
|
||||
self.spin_webp_lossless_level.connect('value-changed',
|
||||
self.on_int_changed, 'webp-lossless-level')
|
||||
|
||||
# JPG Lossy Compression Level
|
||||
self.spin_jpg_lossy_level.set_value(
|
||||
self._settings.get_int('jpg-lossy-level'))
|
||||
self.spin_jpg_lossy_level.connect('value-changed',
|
||||
self.on_int_changed, 'jpg-lossy-level')
|
||||
|
||||
# WEBP Lossy Compression Level
|
||||
self.spin_webp_lossy_level.set_value(
|
||||
self._settings.get_int('webp-lossy-level'))
|
||||
self.spin_webp_lossy_level.connect('value-changed',
|
||||
self.on_int_changed, 'webp-lossy-level')
|
||||
|
||||
# Progressively Encode JPG
|
||||
self.toggle_jpg_progressive.set_active(self._settings.get_boolean('jpg-progressive'))
|
||||
self.toggle_jpg_progressive.connect('notify::active', self.on_bool_changed,
|
||||
|
@ -47,6 +47,7 @@ def add_filechooser_filters(dialog):
|
||||
all_images.set_name(_("All images"))
|
||||
all_images.add_mime_type('image/jpeg')
|
||||
all_images.add_mime_type('image/png')
|
||||
all_images.add_mime_type('image/webp')
|
||||
|
||||
png_images = Gtk.FileFilter()
|
||||
png_images.set_name(_("PNG images"))
|
||||
@ -56,9 +57,14 @@ def add_filechooser_filters(dialog):
|
||||
jpeg_images.set_name(_("JPEG images"))
|
||||
jpeg_images.add_mime_type('image/jpeg')
|
||||
|
||||
webp_images = Gtk.FileFilter()
|
||||
webp_images.set_name(_("WEBP images"))
|
||||
webp_images.add_mime_type('image/webp')
|
||||
|
||||
dialog.add_filter(all_images)
|
||||
dialog.add_filter(png_images)
|
||||
dialog.add_filter(jpeg_images)
|
||||
dialog.add_filter(webp_images)
|
||||
|
||||
|
||||
def get_file_type(filename):
|
||||
@ -68,6 +74,8 @@ def get_file_type(filename):
|
||||
return 'jpg'
|
||||
elif content_type == 'image/png':
|
||||
return 'png'
|
||||
elif content_type == 'image/webp':
|
||||
return 'webp'
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
|
@ -12,11 +12,21 @@
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="webp_lossless_adj">
|
||||
<property name="upper">6</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="png_lossy_adj">
|
||||
<property name="upper">100</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="webp_lossy_adj">
|
||||
<property name="upper">100</property>
|
||||
<property name="step-increment">1</property>
|
||||
<property name="page-increment">10</property>
|
||||
</object>
|
||||
<template class="CurtailPrefsWindow" parent="GtkWindow">
|
||||
<property name="can-focus">False</property>
|
||||
<property name="title" translatable="yes">Preferences</property>
|
||||
@ -198,6 +208,33 @@
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">WEBP Lossy Compression Level</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="spin_webp_lossy_level">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="text">0</property>
|
||||
<property name="adjustment">webp_lossy_adj</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="spin_jpg_lossy_level">
|
||||
<property name="visible">True</property>
|
||||
@ -247,6 +284,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">PNG Lossless Compression Level
|
||||
(the higher it is, the slower it is)</property>
|
||||
</object>
|
||||
@ -255,6 +293,33 @@
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSpinButton" id="spin_webp_lossless_level">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="text">0</property>
|
||||
<property name="adjustment">webp_lossless_adj</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">WEBP Lossless Compression Level
|
||||
(the higher it is, the slower it is)</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
@ -265,7 +330,7 @@
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@ -278,7 +343,7 @@
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
<property name="top-attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -222,7 +222,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')
|
||||
return file_type in ('png', 'jpg', 'webp')
|
||||
else:
|
||||
return False
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user