Skip to content

Commit 9ff73dc

Browse files
author
Jehan
committed
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: mozilla/mozjpeg#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. mozilla/mozjpeg#382 (comment) 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).
1 parent 5e399eb commit 9ff73dc

5 files changed

Lines changed: 42 additions & 4 deletions

File tree

meson.build

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,13 @@ libtiff = dependency('libtiff-4', version: '>=' + libtiff_minver)
667667
MIMEtypes += 'image/tiff'
668668

669669

670-
libjpeg = dependency('libjpeg')
670+
mozjpeg = dependency('mozjpeg', required: get_option('mozjpeg'))
671+
if mozjpeg.found()
672+
libjpeg = mozjpeg
673+
else
674+
libjpeg = dependency('libjpeg')
675+
endif
676+
conf.set('HAVE_MOZJPEG', mozjpeg.found())
671677
MIMEtypes += 'image/jpeg'
672678

673679

@@ -1952,6 +1958,7 @@ final_message = [
19521958
''' Detailed backtraces: @0@'''.format(detailed_backtraces),
19531959
''' Binary symlinks: @0@'''.format(enable_default_bin),
19541960
''' OpenMP: @0@'''.format(have_openmp),
1961+
''' MozJPEG: @0@'''.format(mozjpeg.found()),
19551962
'',
19561963
'''Optional Plug-Ins:''',
19571964
''' Ascii Art: @0@'''.format(libaa.found()),

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ option('ilbm', type: 'feature', value: 'auto', description: 'Amiga
4444
option('jpeg2000', type: 'feature', value: 'auto', description: 'Jpeg-2000 support')
4545
option('jpeg-xl', type: 'feature', value: 'auto', description: 'JPEG XL support')
4646
option('mng', type: 'feature', value: 'auto', description: 'Mng support')
47+
option('mozjpeg', type: 'feature', value: 'auto', description: 'Build JPEG support with mozjpeg specifically')
4748
option('openexr', type: 'feature', value: 'auto', description: 'Openexr support')
4849
option('openmp', type: 'feature', value: 'auto', description: 'OpenMP support')
4950
option('print', type: 'boolean', value: true, description: 'Print support')

plug-ins/file-jpeg/jpeg-save.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ save_image (GFile *file,
198198
GimpImage *image,
199199
GimpDrawable *drawable,
200200
GimpImage *orig_image,
201+
GimpRunMode run_mode,
201202
gboolean preview,
202203
GError **error)
203204
{
@@ -236,6 +237,7 @@ save_image (GFile *file,
236237
gint orig_num_quant_tables = -1;
237238
gboolean use_arithmetic_coding = FALSE;
238239
gboolean use_restart = FALSE;
240+
gboolean mozjpeg = FALSE;
239241
gchar *comment;
240242

241243
g_object_get (config,
@@ -248,6 +250,7 @@ save_image (GFile *file,
248250
"baseline", &baseline,
249251
"restart", &restart,
250252
"dct", &dct,
253+
"use-mozjpeg", &mozjpeg,
251254

252255
/* Original quality settings. */
253256
"use-original-quality", &use_orig_quality,
@@ -262,6 +265,16 @@ save_image (GFile *file,
262265

263266
NULL);
264267

268+
if (run_mode == GIMP_RUN_NONINTERACTIVE && mozjpeg)
269+
{
270+
#ifndef HAVE_MOZJPEG
271+
g_set_error_literal (error, GIMP_PLUG_IN_ERROR, 0,
272+
_("GIMP was not compiled with MozJPEG. "
273+
"The argument 'use-mozjpeg' cannot be set to TRUE."));
274+
return FALSE;
275+
#endif
276+
}
277+
265278
quality = (gint) (dquality * 100.0 + 0.5);
266279

267280
drawable_type = gimp_drawable_type (drawable);
@@ -489,6 +502,13 @@ save_image (GFile *file,
489502
drawable_type == GIMP_RGBA_IMAGE)
490503
? JCS_RGB : JCS_GRAYSCALE;
491504
}
505+
506+
#ifdef HAVE_MOZJPEG
507+
if (! mozjpeg)
508+
/* Disable mozjpeg code path (upstream jpeg-turbo normal algorithm). */
509+
jpeg_c_set_int_param (&cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST);
510+
#endif
511+
492512
/* Now use the library's routine to set default compression parameters.
493513
* (You must set at least cinfo.in_color_space before calling this,
494514
* since the defaults depend on the source color space.)
@@ -795,6 +815,7 @@ make_preview (GimpProcedureConfig *config)
795815
preview_image,
796816
drawable_global,
797817
orig_image_global,
818+
GIMP_RUN_NONINTERACTIVE,
798819
TRUE, NULL);
799820

800821
g_object_unref (file);
@@ -995,6 +1016,9 @@ save_dialog (GimpProcedure *procedure,
9951016
"restart-frame",
9961017
"sub-sampling",
9971018
"dct",
1019+
#ifdef HAVE_MOZJPEG
1020+
"use-mozjpeg",
1021+
#endif
9981022
NULL);
9991023
gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog),
10001024
"advanced-frame", "advanced-title", FALSE,

plug-ins/file-jpeg/jpeg-save.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ extern GimpDrawable *drawable_global;
2424

2525

2626
gboolean save_image (GFile *file,
27-
GimpProcedureConfig *config,
27+
GimpProcedureConfig *config,
2828
GimpImage *image,
2929
GimpDrawable *drawable,
3030
GimpImage *orig_image,
31+
GimpRunMode run_mode,
3132
gboolean preview,
3233
GError **error);
3334
gboolean save_dialog (GimpProcedure *procedure,

plug-ins/file-jpeg/jpeg.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,11 @@ jpeg_create_procedure (GimpPlugIn *plug_in,
301301
_("Use restart mar_kers"),
302302
NULL, FALSE,
303303
G_PARAM_READWRITE);
304+
GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-mozjpeg",
305+
_("Value file size over encoding speed (using MozJPEG)"),
306+
_("Use MozJPEG optimizations for better quality/filesize ratio, with slower encoding."),
307+
FALSE,
308+
G_PARAM_READWRITE);
304309

305310
gimp_save_procedure_set_support_exif (GIMP_SAVE_PROCEDURE (procedure), TRUE);
306311
gimp_save_procedure_set_support_iptc (GIMP_SAVE_PROCEDURE (procedure), TRUE);
@@ -597,8 +602,8 @@ jpeg_save (GimpProcedure *procedure,
597602
if (status == GIMP_PDB_SUCCESS)
598603
{
599604
if (! save_image (file, config,
600-
image, drawables[0], orig_image, FALSE,
601-
&error))
605+
image, drawables[0], orig_image,
606+
run_mode, FALSE, &error))
602607
{
603608
status = GIMP_PDB_EXECUTION_ERROR;
604609
}

0 commit comments

Comments
 (0)