From d47fe45ef14d4f5c4977944829fba1e08a67b861 Mon Sep 17 00:00:00 2001 From: Trevin Chow Date: Sat, 4 Apr 2026 01:59:30 -0700 Subject: [PATCH 1/2] feat: add quality configuration for saving WebP images Add a quality dialog when saving WebP images, matching the existing JPEG quality behavior. When saving a WebP file for the first time in a session, the user is prompted with a quality slider (default 80). - New WebPFormat class following the JpegFormat pattern - Register WebPFormat in ImageConverterManager - Add WEBP_QUALITY setting for persisting the quality value - Generalize quality dialog title from "JPEG Quality" to "Image Quality" Closes #1571 --- Pinta.Core/ImageFormats/WebPFormat.cs | 36 ++++++++++++++++++++ Pinta.Core/Managers/ImageConverterManager.cs | 2 ++ Pinta.Core/SettingNames.cs | 2 ++ Pinta/Dialogs/JpegCompressionDialog.cs | 2 +- 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 Pinta.Core/ImageFormats/WebPFormat.cs diff --git a/Pinta.Core/ImageFormats/WebPFormat.cs b/Pinta.Core/ImageFormats/WebPFormat.cs new file mode 100644 index 0000000000..73f2c82053 --- /dev/null +++ b/Pinta.Core/ImageFormats/WebPFormat.cs @@ -0,0 +1,36 @@ +using System; + +using GdkPixbuf; + +namespace Pinta.Core; + +public sealed class WebPFormat : GdkPixbufFormat +{ + private const int DefaultQuality = 80; + + public WebPFormat () + : base ("webp") + { + } + + protected override void DoSave (Pixbuf pb, Gio.File file, string fileType, Gtk.Window parent) + { + int level = PintaCore.Settings.GetSetting (SettingNames.WEBP_QUALITY, DefaultQuality); + + if (!PintaCore.Workspace.ActiveDocument.HasBeenSavedInSession) { + level = PintaCore.Actions.File.RaiseModifyCompression (level, parent); + + if (level == -1) + throw new OperationCanceledException (); + } + + PintaCore.Settings.PutSetting (SettingNames.WEBP_QUALITY, level); + + using var stream = file.Replace (); + try { + pb.SaveToStreamv (stream, fileType, ["quality"], [level.ToString ()], null); + } finally { + stream.Close (null); + } + } +} diff --git a/Pinta.Core/Managers/ImageConverterManager.cs b/Pinta.Core/Managers/ImageConverterManager.cs index 63d860523e..9a774ecd64 100644 --- a/Pinta.Core/Managers/ImageConverterManager.cs +++ b/Pinta.Core/Managers/ImageConverterManager.cs @@ -87,6 +87,8 @@ private static FormatDescriptor CreateFormatDescriptor (PixbufFormat format) IImageExporter? exporter; if (formatName == "jpeg") exporter = importer = new JpegFormat (); + else if (formatName == "webp") + exporter = importer = new WebPFormat (); else if (formatName == "tga") exporter = new TgaExporter (); else if (format.IsWritable ()) diff --git a/Pinta.Core/SettingNames.cs b/Pinta.Core/SettingNames.cs index 176a5cda6d..570ba6c1f9 100644 --- a/Pinta.Core/SettingNames.cs +++ b/Pinta.Core/SettingNames.cs @@ -6,6 +6,8 @@ internal static class SettingNames internal const string JPG_QUALITY = "jpg-quality"; + internal const string WEBP_QUALITY = "webp-quality"; + internal const string SELECTION_COMBINE_MODE = "selection-combine-mode"; internal const string SHOW_CANVAS_GRID = "show-canvas-grid"; diff --git a/Pinta/Dialogs/JpegCompressionDialog.cs b/Pinta/Dialogs/JpegCompressionDialog.cs index 02ce2afa8b..1c7ed5da90 100644 --- a/Pinta/Dialogs/JpegCompressionDialog.cs +++ b/Pinta/Dialogs/JpegCompressionDialog.cs @@ -43,7 +43,7 @@ public JpegCompressionDialog (int defaultQuality, Gtk.Window parent) // --- Initialization (Gtk.Window) - Title = Translations.GetString ("JPEG Quality"); + Title = Translations.GetString ("Image Quality"); TransientFor = parent; Modal = true; From 91cfad076abfc18bbaa4fd584e138884a91a5c10 Mon Sep 17 00:00:00 2001 From: Trevin Chow Date: Sun, 5 Apr 2026 14:39:14 -0700 Subject: [PATCH 2/2] refactor: rename JpegCompressionDialog to QualityDialog The dialog is now used for both JPEG and WebP quality settings, so the JPEG-specific name no longer fits. --- Pinta/Actions/File/ModifyCompressionAction.cs | 2 +- .../{JpegCompressionDialog.cs => QualityDialog.cs} | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) rename Pinta/Dialogs/{JpegCompressionDialog.cs => QualityDialog.cs} (92%) diff --git a/Pinta/Actions/File/ModifyCompressionAction.cs b/Pinta/Actions/File/ModifyCompressionAction.cs index 011362a028..e608292696 100644 --- a/Pinta/Actions/File/ModifyCompressionAction.cs +++ b/Pinta/Actions/File/ModifyCompressionAction.cs @@ -48,7 +48,7 @@ void IActionHandler.Uninitialize () private void Activated (object? sender, ModifyCompressionEventArgs e) { - JpegCompressionDialog dlg = new (e.Quality, e.ParentWindow); + QualityDialog dlg = new (e.Quality, e.ParentWindow); if (dlg.RunBlocking () == Gtk.ResponseType.Ok) e.Quality = dlg.CompressionLevel; diff --git a/Pinta/Dialogs/JpegCompressionDialog.cs b/Pinta/Dialogs/QualityDialog.cs similarity index 92% rename from Pinta/Dialogs/JpegCompressionDialog.cs rename to Pinta/Dialogs/QualityDialog.cs index 1c7ed5da90..5d8cf3f16a 100644 --- a/Pinta/Dialogs/JpegCompressionDialog.cs +++ b/Pinta/Dialogs/QualityDialog.cs @@ -1,6 +1,6 @@ -// -// JpegCompressionDialog.cs -// +// +// QualityDialog.cs +// // Author: // Maia Kozheva // @@ -28,11 +28,11 @@ namespace Pinta; -public sealed class JpegCompressionDialog : Gtk.Dialog +public sealed class QualityDialog : Gtk.Dialog { private readonly Gtk.Scale compression_level; - public JpegCompressionDialog (int defaultQuality, Gtk.Window parent) + public QualityDialog (int defaultQuality, Gtk.Window parent) { Gtk.Label qualityLabel = Gtk.Label.New (Translations.GetString ("Quality: ")); qualityLabel.Xalign = 0;