Skip to content

Commit

Permalink
Merge pull request OSGeo#11099 from rouault/fix_11095
Browse files Browse the repository at this point in the history
JPEGXL: writer: propagate DISTANCE/QUALITY setting to extra channel
  • Loading branch information
rouault authored Oct 24, 2024
2 parents c735e6c + bafd1ad commit 49675ff
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 10 deletions.
18 changes: 18 additions & 0 deletions autotest/gdrivers/jpegxl.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,24 @@ def test_jpegxl_write_five_bands():
gdal.GetDriverByName("JPEGXL").Delete(outfilename)


def test_jpegxl_write_five_bands_lossy():

drv = gdal.GetDriverByName("JPEGXL")
if drv.GetMetadataItem("JXL_ENCODER_SUPPORT_EXTRA_CHANNELS") is None:
pytest.skip()

src_ds = gdal.Open("data/jpegxl/five_bands.jxl")
outfilename = "/vsimem/out.jxl"
gdal.Translate(outfilename, src_ds, options="-of JPEGXL -co DISTANCE=3 -ot Byte")
ds = gdal.Open(outfilename)
for i in range(5):
assert ds.GetRasterBand(i + 1).ComputeRasterMinMax() == pytest.approx(
(10.0 * (i + 1), 10.0 * (i + 1)), abs=1
)
ds = None
gdal.GetDriverByName("JPEGXL").Delete(outfilename)


def test_jpegxl_createcopy_errors():

outfilename = "/vsimem/out.jxl"
Expand Down
2 changes: 2 additions & 0 deletions doc/source/drivers/raster/jpegxl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ The following creation options are available:
If set to NO, or in AUTO mode if the source dataset does not use JPEG
compression, the regular conversion code path is taken, resulting in a
lossless or lossy copy depending on the LOSSLESS setting.
AUTO mode defaults to NO, if EFFORT, DISTANCE, ALPHA_DISTANCE or QUALITY
options are used.

- .. co:: EFFORT
:choices: 1-9
Expand Down
45 changes: 35 additions & 10 deletions frmts/jpegxl/jpegxl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1798,16 +1798,35 @@ GDALDataset *JPEGXLDataset::CreateCopy(const char *pszFilename,
}
}

constexpr int DEFAULT_EFFORT = 5;
const int nEffort = atoi(CSLFetchNameValueDef(
papszOptions, "EFFORT", CPLSPrintf("%d", DEFAULT_EFFORT)));
const char *pszDistance = CSLFetchNameValue(papszOptions, "DISTANCE");
const char *pszQuality = CSLFetchNameValue(papszOptions, "QUALITY");
const char *pszAlphaDistance =
CSLFetchNameValue(papszOptions, "ALPHA_DISTANCE");
const char *pszLossLessCopy =
CSLFetchNameValueDef(papszOptions, "LOSSLESS_COPY", "AUTO");
if (EQUAL(pszLossLessCopy, "AUTO") || CPLTestBool(pszLossLessCopy))
if ((EQUAL(pszLossLessCopy, "AUTO") && !pszDistance && !pszQuality &&
!pszAlphaDistance && nEffort == DEFAULT_EFFORT) ||
(!EQUAL(pszLossLessCopy, "AUTO") && CPLTestBool(pszLossLessCopy)))
{
void *pJPEGXLContent = nullptr;
size_t nJPEGXLContent = 0;
if (poSrcDS->ReadCompressedData(
"JXL", 0, 0, poSrcDS->GetRasterXSize(),
poSrcDS->GetRasterYSize(), poSrcDS->GetRasterCount(), nullptr,
&pJPEGXLContent, &nJPEGXLContent, nullptr) == CE_None)
const bool bSrcIsJXL =
(poSrcDS->ReadCompressedData(
"JXL", 0, 0, poSrcDS->GetRasterXSize(),
poSrcDS->GetRasterYSize(), poSrcDS->GetRasterCount(), nullptr,
&pJPEGXLContent, &nJPEGXLContent, nullptr) == CE_None);
if (bSrcIsJXL && (pszDistance || pszQuality || pszAlphaDistance ||
nEffort != DEFAULT_EFFORT))
{
CPLError(CE_Failure, CPLE_NotSupported,
"LOSSLESS_COPY=YES not supported when EFFORT, QUALITY, "
"DISTANCE or ALPHA_DISTANCE are specified");
return nullptr;
}
else if (bSrcIsJXL)
{
CPLDebug("JPEGXL", "Lossless copy from source dataset");
GByte abySizeAndBoxName[8];
Expand Down Expand Up @@ -2062,10 +2081,6 @@ GDALDataset *JPEGXLDataset::CreateCopy(const char *pszFilename,
}

const char *pszLossLess = CSLFetchNameValue(papszOptions, "LOSSLESS");
const char *pszDistance = CSLFetchNameValue(papszOptions, "DISTANCE");
const char *pszQuality = CSLFetchNameValue(papszOptions, "QUALITY");
const char *pszAlphaDistance =
CSLFetchNameValue(papszOptions, "ALPHA_DISTANCE");

const bool bLossless = (pszLossLess == nullptr && pszDistance == nullptr &&
pszQuality == nullptr) ||
Expand Down Expand Up @@ -2325,7 +2340,6 @@ GDALDataset *JPEGXLDataset::CreateCopy(const char *pszFilename,
}
}

const int nEffort = atoi(CSLFetchNameValueDef(papszOptions, "EFFORT", "5"));
#ifdef HAVE_JxlEncoderFrameSettingsSetOption
if (JxlEncoderFrameSettingsSetOption(opts, JXL_ENC_FRAME_SETTING_EFFORT,
nEffort) != JXL_ENC_SUCCESS)
Expand Down Expand Up @@ -2572,6 +2586,17 @@ GDALDataset *JPEGXLDataset::CreateCopy(const char *pszFilename,
return nullptr;
}
}
else if (!bLossless)
{
// By default libjxl applies lossless encoding for extra channels
if (JXL_ENC_SUCCESS !=
JxlEncoderSetExtraChannelDistance(opts, nIndex, fDistance))
{
CPLError(CE_Failure, CPLE_AppDefined,
"JxlEncoderSetExtraChannelDistance failed");
return nullptr;
}
}
#endif
}
}
Expand Down

0 comments on commit 49675ff

Please sign in to comment.