From 89678280d2f3c527a9ffffb3b7a55414891a7453 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 18 Apr 2025 08:13:07 +0100 Subject: [PATCH 01/26] New Fork --- lib/extras/enc/jpegli.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 14a7a398..48c75951 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -434,6 +434,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); + float distance = jpegli_quality_to_distance(jpeg_settings.quality); if (!jpeg_settings.chroma_subsampling.empty()) { if (jpeg_settings.chroma_subsampling == "444") { cinfo.comp_info[0].h_samp_factor = 1; @@ -454,11 +455,15 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; } - } else if (!jpeg_settings.xyb) { - // Default is no chroma subsampling. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; - } + } if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) || + (jpeg_settings.quality > 0.0 && jpegli_quality_to_distance(jpeg_settings.quality) >= 6.4)) { + // At lower qualities 420 subsampling begins to outperform 444 + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + } else { + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + } jpegli_enable_adaptive_quantization( &cinfo, TO_JXL_BOOL(jpeg_settings.use_adaptive_quantization)); if (jpeg_settings.psnr_target > 0.0) { From 8a90d97684cb65e67e03e9f93bccf32d68d1a4da Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 18 Apr 2025 08:14:57 +0100 Subject: [PATCH 02/26] New Fork --- lib/jpegli/encode.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index ac4917d2..178822f7 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -783,8 +783,8 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { default: JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace); } - // Adobe marker is only needed to distinguish CMYK and YCCK JPEGs. - cinfo->write_Adobe_marker = TO_JXL_BOOL(cinfo->jpeg_color_space == JCS_YCCK); + // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. + cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_YCCK || cinfo->master->xyb_mode)); if (cinfo->comp_info == nullptr) { cinfo->comp_info = jpegli::Allocate(cinfo, MAX_COMPONENTS); @@ -807,9 +807,9 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].component_id = 'B'; if (cinfo->master->xyb_mode) { // Subsample blue channel. - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - cinfo->comp_info[1].h_samp_factor = cinfo->comp_info[1].v_samp_factor = 2; - cinfo->comp_info[2].h_samp_factor = cinfo->comp_info[2].v_samp_factor = 1; + //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + //cinfo->comp_info[1].h_samp_factor = cinfo->comp_info[1].v_samp_factor = 2; + //cinfo->comp_info[2].h_samp_factor = cinfo->comp_info[2].v_samp_factor = 1; // Use separate quantization tables for each component cinfo->comp_info[1].quant_tbl_no = 1; cinfo->comp_info[2].quant_tbl_no = 2; @@ -826,7 +826,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; // Use chroma subsampling by default - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (colorspace == JCS_YCCK) { cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } From 92355bad38f471f1a9ca36988971518483a5ba4f Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 18 Apr 2025 09:20:06 +0100 Subject: [PATCH 03/26] Comments --- lib/jpegli/encode.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index 178822f7..e361d695 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -806,6 +806,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[1].component_id = 'G'; cinfo->comp_info[2].component_id = 'B'; if (cinfo->master->xyb_mode) { + // Subsampling RGB JPEG is incompatible with JPEG XL transcoding. // Subsample blue channel. //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; //cinfo->comp_info[1].h_samp_factor = cinfo->comp_info[1].v_samp_factor = 2; @@ -825,6 +826,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; + // Subsampling is only useful at low qualities. Check added elsewhere. // Use chroma subsampling by default //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (colorspace == JCS_YCCK) { From c5757c3ea25feab1861479d4c3bd7af499da8656 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 20 Apr 2025 15:10:50 +0100 Subject: [PATCH 04/26] Subsampling default fix --- lib/extras/enc/jpegli.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 48c75951..f6a9e8e9 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -455,12 +455,12 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; } - } if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) || - (jpeg_settings.quality > 0.0 && jpegli_quality_to_distance(jpeg_settings.quality) >= 6.4)) { + } else if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) { // At lower qualities 420 subsampling begins to outperform 444 cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; } else { + // Default to 444 for XYB or medium to high quality cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; } From c7f58cbd3480ffa9de31fc35d0abef0ebe35ac06 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 20 Apr 2025 15:45:54 +0100 Subject: [PATCH 05/26] XYB subsampling spaghetti --- lib/extras/enc/jpegli.cc | 43 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index f6a9e8e9..c2a96dc4 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -435,23 +435,60 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); float distance = jpegli_quality_to_distance(jpeg_settings.quality); + // TODO(Jonnyawsom3): Clean up redundant variables later. + // Ideally use YBX instead of XYB, and try subsampling X too + // to avoid any of this. Subsampling doesn't help XYB much anyway + // but forcing it shouldn't ruin quality, hence spaghetti. if (!jpeg_settings.chroma_subsampling.empty()) { if (jpeg_settings.chroma_subsampling == "444") { + // Set all in case of 444 XYB cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; + if (cinfo->master->xyb_mode) { + // Subsample blue channel for XYB. + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 2; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } } else if (jpeg_settings.chroma_subsampling == "422") { cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; + if (cinfo->master->xyb_mode) { + // Subsample blue channel for XYB. + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 2; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } } else if (jpeg_settings.chroma_subsampling == "420") { cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[0].h_samp_factor = 2; + if (cinfo->master->xyb_mode) { + // Subsample blue channel for XYB. + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 2; + cinfo.comp_info[1].v_samp_factor = 2; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } } else { return false; } - for (int i = 1; i < cinfo.num_components; ++i) { + if (!cinfo->master->xyb_mode) { + for (int i = 1; i < cinfo.num_components; ++i) { cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; } From 3ba68e42b1fd6d06484208fc6df2f9536e473fbb Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 20 Apr 2025 15:51:43 +0100 Subject: [PATCH 06/26] Remove redundant subsampling code --- lib/jpegli/encode.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index e361d695..fcb374d7 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -801,16 +801,12 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { comp->dc_tbl_no = 0; comp->ac_tbl_no = 0; } + // Subsampling is handled in lib/extras/enc/jpegli.cc#L438 if (colorspace == JCS_RGB) { cinfo->comp_info[0].component_id = 'R'; cinfo->comp_info[1].component_id = 'G'; cinfo->comp_info[2].component_id = 'B'; if (cinfo->master->xyb_mode) { - // Subsampling RGB JPEG is incompatible with JPEG XL transcoding. - // Subsample blue channel. - //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - //cinfo->comp_info[1].h_samp_factor = cinfo->comp_info[1].v_samp_factor = 2; - //cinfo->comp_info[2].h_samp_factor = cinfo->comp_info[2].v_samp_factor = 1; // Use separate quantization tables for each component cinfo->comp_info[1].quant_tbl_no = 1; cinfo->comp_info[2].quant_tbl_no = 2; @@ -826,9 +822,6 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; - // Subsampling is only useful at low qualities. Check added elsewhere. - // Use chroma subsampling by default - //cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (colorspace == JCS_YCCK) { cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } From 8183a2a20967ab5794d7d6abdc0d7759987b4d4f Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 20 Apr 2025 18:16:22 +0100 Subject: [PATCH 07/26] Typo --- lib/extras/enc/jpegli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index c2a96dc4..3f6ff502 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -474,7 +474,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } } else if (jpeg_settings.chroma_subsampling == "420") { cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; if (cinfo->master->xyb_mode) { // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; From bd739b894d937c9c9c2b55061b322b1dc141b4af Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:35:14 -0700 Subject: [PATCH 08/26] Compilation fixes --- lib/extras/enc/jpegli.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 3f6ff502..157d188f 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -451,7 +451,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; - if (cinfo->master->xyb_mode) { + if (jpeg_settings.xyb) { // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; @@ -463,7 +463,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } else if (jpeg_settings.chroma_subsampling == "422") { cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; - if (cinfo->master->xyb_mode) { + if (jpeg_settings.xyb) { // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; @@ -475,7 +475,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } else if (jpeg_settings.chroma_subsampling == "420") { cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; - if (cinfo->master->xyb_mode) { + if (jpeg_settings.xyb) { // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; @@ -487,12 +487,13 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } else { return false; } - if (!cinfo->master->xyb_mode) { + if (!jpeg_settings.xyb) { for (int i = 1; i < cinfo.num_components; ++i) { cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; } - } else if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) { + } else if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) || + (jpeg_settings.quality > 0.0 && distance >= 6.4)) { // At lower qualities 420 subsampling begins to outperform 444 cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; From c629732d400625f7a6f63c1fed7df931c522f831 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Sun, 27 Apr 2025 01:37:09 -0700 Subject: [PATCH 09/26] Correct 440 and 422 XYB subsampling --- lib/extras/enc/jpegli.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 157d188f..7eeb52d6 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -453,11 +453,11 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[0].v_samp_factor = 2; if (jpeg_settings.xyb) { // Subsample blue channel for XYB. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 2; cinfo.comp_info[1].v_samp_factor = 2; - cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 2; cinfo.comp_info[2].v_samp_factor = 1; } } else if (jpeg_settings.chroma_subsampling == "422") { @@ -466,11 +466,11 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, if (jpeg_settings.xyb) { // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 2; - cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 2; cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 2; } } else if (jpeg_settings.chroma_subsampling == "420") { cinfo.comp_info[0].h_samp_factor = 2; From 8d6a57974452b5469755310ecabd1e30230d44b9 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 27 Apr 2025 10:30:16 +0100 Subject: [PATCH 10/26] Add APP14 marker to all RGB JPEGs --- lib/jpegli/encode.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index fcb374d7..e7877456 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -784,7 +784,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace); } // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. - cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_YCCK || cinfo->master->xyb_mode)); + cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); if (cinfo->comp_info == nullptr) { cinfo->comp_info = jpegli::Allocate(cinfo, MAX_COMPONENTS); From 68a85424553796cf1db8fa366ac639791f3edabf Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 27 Apr 2025 10:31:58 +0100 Subject: [PATCH 11/26] Comment update --- lib/extras/enc/jpegli.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 7eeb52d6..cc2d16f9 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -436,9 +436,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, jpegli_set_defaults(&cinfo); float distance = jpegli_quality_to_distance(jpeg_settings.quality); // TODO(Jonnyawsom3): Clean up redundant variables later. - // Ideally use YBX instead of XYB, and try subsampling X too - // to avoid any of this. Subsampling doesn't help XYB much anyway - // but forcing it shouldn't ruin quality, hence spaghetti. + // Figure out why H and V are swapped in some cases. if (!jpeg_settings.chroma_subsampling.empty()) { if (jpeg_settings.chroma_subsampling == "444") { // Set all in case of 444 XYB From 41b32c47a56cf259cd1d8928ab645022736467bd Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Sun, 27 Apr 2025 23:36:08 +0100 Subject: [PATCH 12/26] Fixes and comment updates --- lib/extras/enc/jpegli.cc | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index cc2d16f9..e3d370a4 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -435,11 +435,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); float distance = jpegli_quality_to_distance(jpeg_settings.quality); - // TODO(Jonnyawsom3): Clean up redundant variables later. - // Figure out why H and V are swapped in some cases. + // All factors need to be specified to subsample the blue channel + // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { if (jpeg_settings.chroma_subsampling == "444") { - // Set all in case of 444 XYB cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; @@ -450,7 +449,6 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; if (jpeg_settings.xyb) { - // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 2; @@ -462,7 +460,6 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; if (jpeg_settings.xyb) { - // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 2; @@ -474,7 +471,6 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; if (jpeg_settings.xyb) { - // Subsample blue channel for XYB. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 2; @@ -489,14 +485,15 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, for (int i = 1; i < cinfo.num_components; ++i) { cinfo.comp_info[i].h_samp_factor = 1; cinfo.comp_info[i].v_samp_factor = 1; + } } - } else if ((jpeg_settings.distance >= 6.4 && !jpeg_settings.xyb) || + } else if ((jpeg_settings.distance >= 6.4 && colorspace == JCS_YCbCr) || (jpeg_settings.quality > 0.0 && distance >= 6.4)) { - // At lower qualities 420 subsampling begins to outperform 444 + // At low quality, 420 subsampling begins to outperform 444. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; } else { - // Default to 444 for XYB or medium to high quality + // Default to 444 for RGB(XYB) JPEG or medium to high quality. cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; } From 42982712d7d78f47a03bf4e8993d7e3449852c69 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Sun, 27 Apr 2025 15:53:11 -0700 Subject: [PATCH 13/26] Fixed wrong chroma values + redefined used variable --- lib/extras/enc/jpegli.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index e3d370a4..7806dc45 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -434,7 +434,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); - float distance = jpegli_quality_to_distance(jpeg_settings.quality); + float qDistance = jpegli_quality_to_distance(jpeg_settings.quality); // All factors need to be specified to subsample the blue channel // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { @@ -450,7 +450,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, cinfo.comp_info[0].v_samp_factor = 2; if (jpeg_settings.xyb) { cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 2; cinfo.comp_info[1].h_samp_factor = 2; cinfo.comp_info[1].v_samp_factor = 2; cinfo.comp_info[2].h_samp_factor = 2; @@ -488,7 +488,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } } } else if ((jpeg_settings.distance >= 6.4 && colorspace == JCS_YCbCr) || - (jpeg_settings.quality > 0.0 && distance >= 6.4)) { + (jpeg_settings.quality > 0.0 && qDistance >= 6.4)) { // At low quality, 420 subsampling begins to outperform 444. cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 2; From d20292ca01008ab7e5553363ff65418cc224d92f Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Mon, 28 Apr 2025 01:29:30 +0100 Subject: [PATCH 14/26] Move 420 check to encode.cc --- lib/extras/enc/jpegli.cc | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 7806dc45..a5ef3021 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -434,17 +434,13 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); - float qDistance = jpegli_quality_to_distance(jpeg_settings.quality); + // Defaults are set in lib/jpegli/encode.cc#L799 // All factors need to be specified to subsample the blue channel // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { if (jpeg_settings.chroma_subsampling == "444") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; @@ -481,22 +477,7 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } else { return false; } - if (!jpeg_settings.xyb) { - for (int i = 1; i < cinfo.num_components; ++i) { - cinfo.comp_info[i].h_samp_factor = 1; - cinfo.comp_info[i].v_samp_factor = 1; - } - } - } else if ((jpeg_settings.distance >= 6.4 && colorspace == JCS_YCbCr) || - (jpeg_settings.quality > 0.0 && qDistance >= 6.4)) { - // At low quality, 420 subsampling begins to outperform 444. - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - } else { - // Default to 444 for RGB(XYB) JPEG or medium to high quality. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; - } + } jpegli_enable_adaptive_quantization( &cinfo, TO_JXL_BOOL(jpeg_settings.use_adaptive_quantization)); if (jpeg_settings.psnr_target > 0.0) { From ace997f733ea08c382d53cf990e427348f1e52d6 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Mon, 28 Apr 2025 01:30:06 +0100 Subject: [PATCH 15/26] Move 420 check from jpegli.cc and fix APP14 CMYK --- lib/jpegli/encode.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index e7877456..f79be80b 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -784,7 +784,8 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace); } // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. - cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); + cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_CMYK || + cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); if (cinfo->comp_info == nullptr) { cinfo->comp_info = jpegli::Allocate(cinfo, MAX_COMPONENTS); @@ -795,21 +796,21 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { jpeg_component_info* comp = &cinfo->comp_info[c]; comp->component_index = c; comp->component_id = c + 1; + // Default is no chroma subsampling. comp->h_samp_factor = 1; comp->v_samp_factor = 1; comp->quant_tbl_no = 0; comp->dc_tbl_no = 0; comp->ac_tbl_no = 0; } - // Subsampling is handled in lib/extras/enc/jpegli.cc#L438 if (colorspace == JCS_RGB) { cinfo->comp_info[0].component_id = 'R'; cinfo->comp_info[1].component_id = 'G'; cinfo->comp_info[2].component_id = 'B'; if (cinfo->master->xyb_mode) { - // Use separate quantization tables for each component - cinfo->comp_info[1].quant_tbl_no = 1; - cinfo->comp_info[2].quant_tbl_no = 2; + // Use separate quantization tables for each component + cinfo->comp_info[1].quant_tbl_no = 1; + cinfo->comp_info[2].quant_tbl_no = 2; } } else if (colorspace == JCS_CMYK) { cinfo->comp_info[0].component_id = 'C'; @@ -822,8 +823,14 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; + // At low quality, 420 subsampling begins to outperform 444. + float qDistance = jpegli_quality_to_distance(jpeg_settings.quality); + if (jpeg_settings.distance >= 6.4 || + (jpeg_settings.quality > 0.0 && qDistance >= 6.4)) { + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (colorspace == JCS_YCCK) { - cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + } } } } From 5419b9b2f96d593dafc58cd3125baed031850170 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Mon, 28 Apr 2025 18:40:03 -0700 Subject: [PATCH 16/26] Compile Fixes --- lib/jpegli/encode.cc | 114 ++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 49 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index f79be80b..a4e2527e 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -717,6 +717,65 @@ void jpegli_set_defaults(j_compress_ptr cinfo) { /*is_dc=*/true); } +bool auto420 = false; +bool q100RGB = false; + +void jpegli_set_distance(j_compress_ptr cinfo, float distance, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); + if (distance >= 6.4) { + auto420 = true; + } + // At quality 100 (distance 0) auto select RGB colorspace. + if (distance == 0) { + q100RGB = true; + } +} + +float jpegli_quality_to_distance(int quality) { + return (quality >= 100 ? 0.01f + : quality >= 30 ? 0.1f + (100 - quality) * 0.09f + : 53.0f / 3000.0f * quality * quality - + 23.0f / 20.0f * quality + 25.0f); +} + +void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance, + float min_distance, float max_distance) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->psnr_target = psnr; + cinfo->master->psnr_tolerance = tolerance; + cinfo->master->min_distance = min_distance; + cinfo->master->max_distance = max_distance; +} + +void jpegli_set_quality(j_compress_ptr cinfo, int quality, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distance = jpegli_quality_to_distance(quality); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); + if (distance >= 6.4) { + auto420 = true; + } + // At quality 100 (distance 0) auto select RGB colorspace. + if (distance == 0) { + q100RGB = true; + } +} + +void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distance = jpegli::LinearQualityToDistance(scale_factor); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); +} + void jpegli_default_colorspace(j_compress_ptr cinfo) { CheckState(cinfo, jpegli::kEncStart); if (cinfo->in_color_space == JCS_RGB && cinfo->master->xyb_mode) { @@ -823,60 +882,17 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; - // At low quality, 420 subsampling begins to outperform 444. - float qDistance = jpegli_quality_to_distance(jpeg_settings.quality); - if (jpeg_settings.distance >= 6.4 || - (jpeg_settings.quality > 0.0 && qDistance >= 6.4)) { + // At low qualities, 420 subsampling begins to outperform 444. + // Therefore it's enabled by default. + if (auto420) { cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - if (colorspace == JCS_YCCK) { - cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; - } + if (colorspace == JCS_YCCK) { + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + } } } } -void jpegli_set_distance(j_compress_ptr cinfo, float distance, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); -} - -float jpegli_quality_to_distance(int quality) { - return (quality >= 100 ? 0.01f - : quality >= 30 ? 0.1f + (100 - quality) * 0.09f - : 53.0f / 3000.0f * quality * quality - - 23.0f / 20.0f * quality + 25.0f); -} - -void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance, - float min_distance, float max_distance) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->psnr_target = psnr; - cinfo->master->psnr_tolerance = tolerance; - cinfo->master->min_distance = min_distance; - cinfo->master->max_distance = max_distance; -} - -void jpegli_set_quality(j_compress_ptr cinfo, int quality, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distance = jpegli_quality_to_distance(quality); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); -} - -void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distance = jpegli::LinearQualityToDistance(scale_factor); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); -} - #if JPEG_LIB_VERSION >= 70 void jpegli_default_qtables(j_compress_ptr cinfo, boolean force_baseline) { CheckState(cinfo, jpegli::kEncStart); From 0dc619f00ea8a8ed96cd0172a61bbb71006c2fab Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Wed, 30 Apr 2025 18:57:19 -0700 Subject: [PATCH 17/26] Rebase --- lib/jpegli/encode.cc | 142 ++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 70 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index a4e2527e..334b1688 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -717,65 +717,6 @@ void jpegli_set_defaults(j_compress_ptr cinfo) { /*is_dc=*/true); } -bool auto420 = false; -bool q100RGB = false; - -void jpegli_set_distance(j_compress_ptr cinfo, float distance, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); - if (distance >= 6.4) { - auto420 = true; - } - // At quality 100 (distance 0) auto select RGB colorspace. - if (distance == 0) { - q100RGB = true; - } -} - -float jpegli_quality_to_distance(int quality) { - return (quality >= 100 ? 0.01f - : quality >= 30 ? 0.1f + (100 - quality) * 0.09f - : 53.0f / 3000.0f * quality * quality - - 23.0f / 20.0f * quality + 25.0f); -} - -void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance, - float min_distance, float max_distance) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->psnr_target = psnr; - cinfo->master->psnr_tolerance = tolerance; - cinfo->master->min_distance = min_distance; - cinfo->master->max_distance = max_distance; -} - -void jpegli_set_quality(j_compress_ptr cinfo, int quality, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distance = jpegli_quality_to_distance(quality); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); - if (distance >= 6.4) { - auto420 = true; - } - // At quality 100 (distance 0) auto select RGB colorspace. - if (distance == 0) { - q100RGB = true; - } -} - -void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor, - boolean force_baseline) { - CheckState(cinfo, jpegli::kEncStart); - cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distance = jpegli::LinearQualityToDistance(scale_factor); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); -} - void jpegli_default_colorspace(j_compress_ptr cinfo) { CheckState(cinfo, jpegli::kEncStart); if (cinfo->in_color_space == JCS_RGB && cinfo->master->xyb_mode) { @@ -842,9 +783,9 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { default: JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace); } - // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. + // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_CMYK || - cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); + cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); if (cinfo->comp_info == nullptr) { cinfo->comp_info = jpegli::Allocate(cinfo, MAX_COMPONENTS); @@ -855,7 +796,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { jpeg_component_info* comp = &cinfo->comp_info[c]; comp->component_index = c; comp->component_id = c + 1; - // Default is no chroma subsampling. + // Default is no chroma subsampling. comp->h_samp_factor = 1; comp->v_samp_factor = 1; comp->quant_tbl_no = 0; @@ -867,9 +808,9 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[1].component_id = 'G'; cinfo->comp_info[2].component_id = 'B'; if (cinfo->master->xyb_mode) { - // Use separate quantization tables for each component - cinfo->comp_info[1].quant_tbl_no = 1; - cinfo->comp_info[2].quant_tbl_no = 2; + // Use separate quantization tables for each component + cinfo->comp_info[1].quant_tbl_no = 1; + cinfo->comp_info[2].quant_tbl_no = 2; } } else if (colorspace == JCS_CMYK) { cinfo->comp_info[0].component_id = 'C'; @@ -882,17 +823,78 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; - // At low qualities, 420 subsampling begins to outperform 444. - // Therefore it's enabled by default. - if (auto420) { + // Use chroma subsampling by default cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - if (colorspace == JCS_YCCK) { + if (colorspace == JCS_YCCK) { cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; - } } } } +void jpegli_set_distance(j_compress_ptr cinfo, float distance, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); + if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { + // At low qualities, 420 subsampling begins to outperform 444. + // Therefore it's enabled by default. + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + } + // At quality 100 (distance 0) auto select RGB colorspace. + // Disable adaptive quantization since it's unnecessary. + if (distance < 0.02f) { + jpegli_set_colorspace(cinfo, JCS_RGB); + cinfo->master->use_adaptive_quantization = false; + } +} + +float jpegli_quality_to_distance(int quality) { + return (quality >= 100 ? 0.00f + : quality >= 30 ? 0.1f + (100 - quality) * 0.09f + : 53.0f / 3000.0f * quality * quality - + 23.0f / 20.0f * quality + 25.0f); +} + +void jpegli_set_psnr(j_compress_ptr cinfo, float psnr, float tolerance, + float min_distance, float max_distance) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->psnr_target = psnr; + cinfo->master->psnr_tolerance = tolerance; + cinfo->master->min_distance = min_distance; + cinfo->master->max_distance = max_distance; +} + +void jpegli_set_quality(j_compress_ptr cinfo, int quality, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distance = jpegli_quality_to_distance(quality); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); + if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { + // At low qualities, 420 subsampling begins to outperform 444. + // Therefore it's enabled by default. + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + } + // At quality 100 (distance 0) auto select RGB colorspace. + // Disable adaptive quantization since it's unnecessary. + if (distance < 0.02f) { + jpegli_set_colorspace(cinfo, JCS_RGB); + cinfo->master->use_adaptive_quantization = false; + } +} + +void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor, + boolean force_baseline) { + CheckState(cinfo, jpegli::kEncStart); + cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); + float distance = jpegli::LinearQualityToDistance(scale_factor); + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); +} + #if JPEG_LIB_VERSION >= 70 void jpegli_default_qtables(j_compress_ptr cinfo, boolean force_baseline) { CheckState(cinfo, jpegli::kEncStart); From 49f340eb3fe857175cb0b0269fbcdaed746b23a3 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Wed, 30 Apr 2025 19:17:07 -0700 Subject: [PATCH 18/26] Add checks --- lib/jpegli/encode.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index 334b1688..99812734 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -796,7 +796,7 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { jpeg_component_info* comp = &cinfo->comp_info[c]; comp->component_index = c; comp->component_id = c + 1; - // Default is no chroma subsampling. + // Default is no chroma subsampling. comp->h_samp_factor = 1; comp->v_samp_factor = 1; comp->quant_tbl_no = 0; @@ -838,13 +838,13 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { - // At low qualities, 420 subsampling begins to outperform 444. + // At low qualities, 420 subsampling begins to outperform 444. // Therefore it's enabled by default. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; } // At quality 100 (distance 0) auto select RGB colorspace. // Disable adaptive quantization since it's unnecessary. - if (distance < 0.02f) { + if (distance < 0.01f && cinfo->in_color_space == JCS_RGB) { jpegli_set_colorspace(cinfo, JCS_RGB); cinfo->master->use_adaptive_quantization = false; } @@ -874,13 +874,13 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { - // At low qualities, 420 subsampling begins to outperform 444. + // At low qualities, 420 subsampling begins to outperform 444. // Therefore it's enabled by default. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; } // At quality 100 (distance 0) auto select RGB colorspace. // Disable adaptive quantization since it's unnecessary. - if (distance < 0.02f) { + if (distance < 0.01f && cinfo->in_color_space == JCS_RGB) { jpegli_set_colorspace(cinfo, JCS_RGB); cinfo->master->use_adaptive_quantization = false; } From 3c35af44c6373960eccd0e2ab440df62eeb05bee Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Thu, 1 May 2025 23:40:44 -0700 Subject: [PATCH 19/26] Update encode_internal.h --- lib/jpegli/encode_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jpegli/encode_internal.h b/lib/jpegli/encode_internal.h index 3f5d1a76..b0236a6a 100644 --- a/lib/jpegli/encode_internal.h +++ b/lib/jpegli/encode_internal.h @@ -75,6 +75,7 @@ struct jpeg_comp_master { uint8_t cicp_transfer_function; bool use_std_tables; bool use_adaptive_quantization; + bool chroma_subsampling_set_by_cli = false; int progressive_level; size_t xsize_blocks; size_t ysize_blocks; From d02e24516302c48249d9f6810c0688f852299466 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Thu, 1 May 2025 23:41:48 -0700 Subject: [PATCH 20/26] Update jpegli.cc --- lib/extras/enc/jpegli.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index a5ef3021..c428fe49 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -34,6 +34,7 @@ #include "lib/extras/xyb_transform.h" #include "lib/jpegli/common.h" #include "lib/jpegli/encode.h" +#include "lib/jpegli/encode_internal.h" #include "lib/jpegli/types.h" namespace jxl { @@ -438,9 +439,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, // All factors need to be specified to subsample the blue channel // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { +// cinfo.master->chroma_subsampling_set_by_cli = true; if (jpeg_settings.chroma_subsampling == "444") { cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; From dce05322f656154de3aef6cb2665554ee19523ca Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Thu, 1 May 2025 23:42:10 -0700 Subject: [PATCH 21/26] update encode.cc --- lib/jpegli/encode.cc | 45 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index 99812734..6a3247bd 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -823,11 +823,6 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { cinfo->comp_info[2].quant_tbl_no = 1; cinfo->comp_info[1].dc_tbl_no = cinfo->comp_info[1].ac_tbl_no = 1; cinfo->comp_info[2].dc_tbl_no = cinfo->comp_info[2].ac_tbl_no = 1; - // Use chroma subsampling by default - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - if (colorspace == JCS_YCCK) { - cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; - } } } @@ -835,19 +830,21 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, boolean force_baseline) { CheckState(cinfo, jpegli::kEncStart); cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); - if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { - // At low qualities, 420 subsampling begins to outperform 444. - // Therefore it's enabled by default. + if (distance >= 1.9f && !(cinfo->master->xyb_mode) && + !cinfo->master->chroma_subsampling_set_by_cli) { + // At medium qualities, 420 subsampling begins to outperform 444. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; } + // Disable adaptive quantization at high qualities. + if (distance <= 1.0f) { + cinfo->master->use_adaptive_quantization = false; + } // At quality 100 (distance 0) auto select RGB colorspace. - // Disable adaptive quantization since it's unnecessary. - if (distance < 0.01f && cinfo->in_color_space == JCS_RGB) { - jpegli_set_colorspace(cinfo, JCS_RGB); - cinfo->master->use_adaptive_quantization = false; + if (distance <= 0.01f && cinfo->in_color_space == JCS_RGB) { + jpegli_set_colorspace(cinfo, JCS_RGB); } + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); } float jpegli_quality_to_distance(int quality) { @@ -871,19 +868,21 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, CheckState(cinfo, jpegli::kEncStart); cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); float distance = jpegli_quality_to_distance(quality); - float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; - jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); - if (distance >= 6.4 && !(cinfo->master->xyb_mode)) { - // At low qualities, 420 subsampling begins to outperform 444. - // Therefore it's enabled by default. + if (distance >= 1.9f && !(cinfo->master->xyb_mode) && + !cinfo->master->chroma_subsampling_set_by_cli) { + // At medium qualities, 420 subsampling begins to outperform 444. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; } + // Disable adaptive quantization at high qualities. + if (distance <= 1.0f) { + cinfo->master->use_adaptive_quantization = false; + } // At quality 100 (distance 0) auto select RGB colorspace. - // Disable adaptive quantization since it's unnecessary. - if (distance < 0.01f && cinfo->in_color_space == JCS_RGB) { - jpegli_set_colorspace(cinfo, JCS_RGB); - cinfo->master->use_adaptive_quantization = false; + if (distance <= 0.01f && cinfo->in_color_space == JCS_RGB) { + jpegli_set_colorspace(cinfo, JCS_RGB); } + float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; + jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false); } void jpegli_set_linear_quality(j_compress_ptr cinfo, int scale_factor, From 3cce60bf52794d20014c28a24444a36b43e3143b Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Thu, 1 May 2025 23:47:29 -0700 Subject: [PATCH 22/26] oops small fix :P --- lib/extras/enc/jpegli.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index c428fe49..7cac2936 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -439,10 +439,10 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, // All factors need to be specified to subsample the blue channel // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { -// cinfo.master->chroma_subsampling_set_by_cli = true; + cinfo.master->chroma_subsampling_set_by_cli = true; if (jpeg_settings.chroma_subsampling == "444") { cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; From 46569f86dbe9321b314e15d9861e5ea8664948f3 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Fri, 2 May 2025 00:02:42 -0700 Subject: [PATCH 23/26] oops! another small fix :P --- lib/jpegli/encode.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index 6a3247bd..fb3aaced 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -833,8 +833,11 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, if (distance >= 1.9f && !(cinfo->master->xyb_mode) && !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + if (cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_CMYK) { + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } + } // Disable adaptive quantization at high qualities. if (distance <= 1.0f) { cinfo->master->use_adaptive_quantization = false; @@ -871,8 +874,11 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, if (distance >= 1.9f && !(cinfo->master->xyb_mode) && !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + if (cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_CMYK) { + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } + } // Disable adaptive quantization at high qualities. if (distance <= 1.0f) { cinfo->master->use_adaptive_quantization = false; From 0fb8fe8b1b52bd253cb33214f0e907a0024c5e85 Mon Sep 17 00:00:00 2001 From: Galaxy4594 <164440799+Galaxy4594@users.noreply.github.com> Date: Fri, 2 May 2025 00:13:59 -0700 Subject: [PATCH 24/26] Remove CMYK subsampling --- lib/jpegli/encode.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index fb3aaced..f0d328a3 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -834,7 +834,7 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - if (cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_CMYK) { + if (cinfo->jpeg_color_space == JCS_YCCK) { cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } } @@ -875,7 +875,7 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; - if (cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_CMYK) { + if (cinfo->jpeg_color_space == JCS_YCCK) { cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } } From d167eb19d56ac99aa0a43c4c45e8659432cd7421 Mon Sep 17 00:00:00 2001 From: Jonathan Brown Date: Fri, 2 May 2025 19:34:36 +0100 Subject: [PATCH 25/26] Keep Adaptive Quantization for XYB --- lib/jpegli/encode.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index f0d328a3..67f0a7bf 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -839,7 +839,7 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, } } // Disable adaptive quantization at high qualities. - if (distance <= 1.0f) { + if (distance <= 1.0f && !(cinfo->master->xyb_mode)) { cinfo->master->use_adaptive_quantization = false; } // At quality 100 (distance 0) auto select RGB colorspace. @@ -880,7 +880,7 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, } } // Disable adaptive quantization at high qualities. - if (distance <= 1.0f) { + if (distance <= 1.0f && !(cinfo->master->xyb_mode)) { cinfo->master->use_adaptive_quantization = false; } // At quality 100 (distance 0) auto select RGB colorspace. From bb7e2fe1e4cb523370aff0fca1a1072dd50d3ae8 Mon Sep 17 00:00:00 2001 From: Damon Townsend Date: Tue, 6 May 2025 10:49:20 -0700 Subject: [PATCH 26/26] lint --- lib/extras/enc/jpegli.cc | 55 ++++++++++++++++++++-------------------- lib/jpegli/encode.cc | 26 ++++++++++--------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/extras/enc/jpegli.cc b/lib/extras/enc/jpegli.cc index 7cac2936..461cfbe3 100644 --- a/lib/extras/enc/jpegli.cc +++ b/lib/extras/enc/jpegli.cc @@ -435,47 +435,46 @@ Status EncodeJpeg(const PackedPixelFile& ppf, const JpegSettings& jpeg_settings, } jpegli_set_cicp_transfer_function(&cinfo, cicp_tf); jpegli_set_defaults(&cinfo); - // Defaults are set in lib/jpegli/encode.cc#L799 // All factors need to be specified to subsample the blue channel // for XYB. H and V are swapped between YCbCr and XYB. if (!jpeg_settings.chroma_subsampling.empty()) { - cinfo.master->chroma_subsampling_set_by_cli = true; + cinfo.master->chroma_subsampling_set_by_cli = true; if (jpeg_settings.chroma_subsampling == "444") { cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; } else if (jpeg_settings.chroma_subsampling == "440") { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 2; - if (jpeg_settings.xyb) { - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 2; - cinfo.comp_info[1].v_samp_factor = 2; - cinfo.comp_info[2].h_samp_factor = 2; - cinfo.comp_info[2].v_samp_factor = 1; - } + if (jpeg_settings.xyb) { + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 2; + cinfo.comp_info[1].v_samp_factor = 2; + cinfo.comp_info[2].h_samp_factor = 2; + cinfo.comp_info[2].v_samp_factor = 1; + } } else if (jpeg_settings.chroma_subsampling == "422") { cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; - if (jpeg_settings.xyb) { - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 2; - cinfo.comp_info[1].v_samp_factor = 2; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 2; - } + if (jpeg_settings.xyb) { + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 2; + cinfo.comp_info[1].v_samp_factor = 2; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 2; + } } else if (jpeg_settings.chroma_subsampling == "420") { cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - if (jpeg_settings.xyb) { - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 2; - cinfo.comp_info[1].v_samp_factor = 2; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; - } + cinfo.comp_info[0].v_samp_factor = 2; + if (jpeg_settings.xyb) { + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 2; + cinfo.comp_info[1].v_samp_factor = 2; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + } } else { return false; } diff --git a/lib/jpegli/encode.cc b/lib/jpegli/encode.cc index 67f0a7bf..af3c8cbf 100644 --- a/lib/jpegli/encode.cc +++ b/lib/jpegli/encode.cc @@ -784,8 +784,10 @@ void jpegli_set_colorspace(j_compress_ptr cinfo, J_COLOR_SPACE colorspace) { JPEGLI_ERROR("Unsupported jpeg colorspace %d", colorspace); } // Adobe marker is needed to distinguish CMYK, YCCK and RGB(XYB) JPEGs. - cinfo->write_Adobe_marker = TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_CMYK || - cinfo->jpeg_color_space == JCS_YCCK || cinfo->jpeg_color_space == JCS_RGB)); + cinfo->write_Adobe_marker = + TO_JXL_BOOL((cinfo->jpeg_color_space == JCS_CMYK || + cinfo->jpeg_color_space == JCS_YCCK || + cinfo->jpeg_color_space == JCS_RGB)); if (cinfo->comp_info == nullptr) { cinfo->comp_info = jpegli::Allocate(cinfo, MAX_COMPONENTS); @@ -831,20 +833,20 @@ void jpegli_set_distance(j_compress_ptr cinfo, float distance, CheckState(cinfo, jpegli::kEncStart); cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); if (distance >= 1.9f && !(cinfo->master->xyb_mode) && - !cinfo->master->chroma_subsampling_set_by_cli) { + !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (cinfo->jpeg_color_space == JCS_YCCK) { - cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } } // Disable adaptive quantization at high qualities. if (distance <= 1.0f && !(cinfo->master->xyb_mode)) { - cinfo->master->use_adaptive_quantization = false; + cinfo->master->use_adaptive_quantization = false; } // At quality 100 (distance 0) auto select RGB colorspace. if (distance <= 0.01f && cinfo->in_color_space == JCS_RGB) { - jpegli_set_colorspace(cinfo, JCS_RGB); + jpegli_set_colorspace(cinfo, JCS_RGB); } float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/true); @@ -872,20 +874,20 @@ void jpegli_set_quality(j_compress_ptr cinfo, int quality, cinfo->master->force_baseline = FROM_JXL_BOOL(force_baseline); float distance = jpegli_quality_to_distance(quality); if (distance >= 1.9f && !(cinfo->master->xyb_mode) && - !cinfo->master->chroma_subsampling_set_by_cli) { + !cinfo->master->chroma_subsampling_set_by_cli) { // At medium qualities, 420 subsampling begins to outperform 444. - cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[0].h_samp_factor = cinfo->comp_info[0].v_samp_factor = 2; if (cinfo->jpeg_color_space == JCS_YCCK) { - cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; + cinfo->comp_info[3].h_samp_factor = cinfo->comp_info[3].v_samp_factor = 2; } } // Disable adaptive quantization at high qualities. if (distance <= 1.0f && !(cinfo->master->xyb_mode)) { - cinfo->master->use_adaptive_quantization = false; + cinfo->master->use_adaptive_quantization = false; } // At quality 100 (distance 0) auto select RGB colorspace. if (distance <= 0.01f && cinfo->in_color_space == JCS_RGB) { - jpegli_set_colorspace(cinfo, JCS_RGB); + jpegli_set_colorspace(cinfo, JCS_RGB); } float distances[NUM_QUANT_TBLS] = {distance, distance, distance}; jpegli::SetQuantMatrices(cinfo, distances, /*add_two_chroma_tables=*/false);