1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-06 01:12:40 +02:00

plug-ins: new JPEG export option to value file size over encoding speed.

This uses MozJPEG from Mozilla and is dependent on this patch to be merged:
https://github.com/mozilla/mozjpeg/pull/383
This is an optional option (standard libjpeg API, e.g. with jpeg-turbo, is still
used when MozJPEG is not detected at build time).

When using MozJPEG, we have access to both the standard algorithm used by
libjpeg-turbo, since MozJPEG is a patched version of libjpeg-turbo, and their
own encoding algorithm. We can switch from one to another with a single call.

Here is what the maintainer says about MozJPEG goal:

> The point of MozJPEG is to improve quality/filesize ratio. It's a win-win: you
> get better quality for the same file size, or better file size for the same
> quality, or both. There is no downside in either quality or file size. MozJPEG
> tunes for these two aspects over speed. libjpeg-turbo's maintainer values speed
> over the other two variables.
>
> MozJPEG has a few techniques. Improved splitting of progressive scans gives
> smaller file size while being 100% visually identical with libjpeg-turbo.
>
> But MozJPEG also has trellis quantization and tuned quantization tables that
> give better visual quality, but on a microscopic scale they make different
> choices than libjpeg-turbo, so some pixels differ. The differences are
> relatively small and predictable, so there's no risk of unexpectedly ruining
> an image (especially that on average, you get better quality).

Cf. https://github.com/mozilla/mozjpeg/issues/382#issuecomment-730544796

Note that after several testing, I could indeed confirm that it seems to always
produce smaller files (as far as my testing went) for similarly looking quality,
but the speed cost can actually be quite important: on my computer, for some
random files where encoding would take 0.7 second, it took 3.5 secs with
mozjpeg; for much bigger file (~25MiB) where export with jpeg-turbo takes about
3.9 secs, it takes 30+ seconds with MozJPEG which is a huge difference and can
be very frustrating.
For small files only, this is less of a problem (I still timed an important
difference, but from 0.05 to 0.15 secs is actually bearable).

This is why this cannot be an option checked by default.

About naming: I hesitated to call it "Export for Web" because it's clearly one
of the big use cases (optimizing file size for images on websites), but I just
decided to go with a much more explicit name (even though it may resonate less
that the basic "Export for Web" which everyone asks for).
This commit is contained in:
Jehan
2023-09-07 18:14:13 +02:00
parent 5e399ebd2b
commit 9ff73dc26a
5 changed files with 42 additions and 4 deletions

View File

@@ -667,7 +667,13 @@ libtiff = dependency('libtiff-4', version: '>=' + libtiff_minver)
MIMEtypes += 'image/tiff'
libjpeg = dependency('libjpeg')
mozjpeg = dependency('mozjpeg', required: get_option('mozjpeg'))
if mozjpeg.found()
libjpeg = mozjpeg
else
libjpeg = dependency('libjpeg')
endif
conf.set('HAVE_MOZJPEG', mozjpeg.found())
MIMEtypes += 'image/jpeg'
@@ -1952,6 +1958,7 @@ final_message = [
''' Detailed backtraces: @0@'''.format(detailed_backtraces),
''' Binary symlinks: @0@'''.format(enable_default_bin),
''' OpenMP: @0@'''.format(have_openmp),
''' MozJPEG: @0@'''.format(mozjpeg.found()),
'',
'''Optional Plug-Ins:''',
''' Ascii Art: @0@'''.format(libaa.found()),

View File

@@ -44,6 +44,7 @@ option('ilbm', type: 'feature', value: 'auto', description: 'Amiga
option('jpeg2000', type: 'feature', value: 'auto', description: 'Jpeg-2000 support')
option('jpeg-xl', type: 'feature', value: 'auto', description: 'JPEG XL support')
option('mng', type: 'feature', value: 'auto', description: 'Mng support')
option('mozjpeg', type: 'feature', value: 'auto', description: 'Build JPEG support with mozjpeg specifically')
option('openexr', type: 'feature', value: 'auto', description: 'Openexr support')
option('openmp', type: 'feature', value: 'auto', description: 'OpenMP support')
option('print', type: 'boolean', value: true, description: 'Print support')

View File

@@ -198,6 +198,7 @@ save_image (GFile *file,
GimpImage *image,
GimpDrawable *drawable,
GimpImage *orig_image,
GimpRunMode run_mode,
gboolean preview,
GError **error)
{
@@ -236,6 +237,7 @@ save_image (GFile *file,
gint orig_num_quant_tables = -1;
gboolean use_arithmetic_coding = FALSE;
gboolean use_restart = FALSE;
gboolean mozjpeg = FALSE;
gchar *comment;
g_object_get (config,
@@ -248,6 +250,7 @@ save_image (GFile *file,
"baseline", &baseline,
"restart", &restart,
"dct", &dct,
"use-mozjpeg", &mozjpeg,
/* Original quality settings. */
"use-original-quality", &use_orig_quality,
@@ -262,6 +265,16 @@ save_image (GFile *file,
NULL);
if (run_mode == GIMP_RUN_NONINTERACTIVE && mozjpeg)
{
#ifndef HAVE_MOZJPEG
g_set_error_literal (error, GIMP_PLUG_IN_ERROR, 0,
_("GIMP was not compiled with MozJPEG. "
"The argument 'use-mozjpeg' cannot be set to TRUE."));
return FALSE;
#endif
}
quality = (gint) (dquality * 100.0 + 0.5);
drawable_type = gimp_drawable_type (drawable);
@@ -489,6 +502,13 @@ save_image (GFile *file,
drawable_type == GIMP_RGBA_IMAGE)
? JCS_RGB : JCS_GRAYSCALE;
}
#ifdef HAVE_MOZJPEG
if (! mozjpeg)
/* Disable mozjpeg code path (upstream jpeg-turbo normal algorithm). */
jpeg_c_set_int_param (&cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST);
#endif
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
@@ -795,6 +815,7 @@ make_preview (GimpProcedureConfig *config)
preview_image,
drawable_global,
orig_image_global,
GIMP_RUN_NONINTERACTIVE,
TRUE, NULL);
g_object_unref (file);
@@ -995,6 +1016,9 @@ save_dialog (GimpProcedure *procedure,
"restart-frame",
"sub-sampling",
"dct",
#ifdef HAVE_MOZJPEG
"use-mozjpeg",
#endif
NULL);
gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
"advanced-frame", "advanced-title", FALSE,

View File

@@ -24,10 +24,11 @@ extern GimpDrawable *drawable_global;
gboolean save_image (GFile *file,
GimpProcedureConfig *config,
GimpProcedureConfig *config,
GimpImage *image,
GimpDrawable *drawable,
GimpImage *orig_image,
GimpRunMode run_mode,
gboolean preview,
GError **error);
gboolean save_dialog (GimpProcedure *procedure,

View File

@@ -301,6 +301,11 @@ jpeg_create_procedure (GimpPlugIn *plug_in,
_("Use restart mar_kers"),
NULL, FALSE,
G_PARAM_READWRITE);
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-mozjpeg",
_("Value file size over encoding speed (using MozJPEG)"),
_("Use MozJPEG optimizations for better quality/filesize ratio, with slower encoding."),
FALSE,
G_PARAM_READWRITE);
gimp_save_procedure_set_support_exif (GIMP_SAVE_PROCEDURE (procedure), TRUE);
gimp_save_procedure_set_support_iptc (GIMP_SAVE_PROCEDURE (procedure), TRUE);
@@ -597,8 +602,8 @@ jpeg_save (GimpProcedure *procedure,
if (status == GIMP_PDB_SUCCESS)
{
if (! save_image (file, config,
image, drawables[0], orig_image, FALSE,
&error))
image, drawables[0], orig_image,
run_mode, FALSE, &error))
{
status = GIMP_PDB_EXECUTION_ERROR;
}