Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-picking #67

Merged
merged 19 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ if(JPEGXL_ENABLE_MANPAGES)
find_program(ASCIIDOC a2x)
if(ASCIIDOC)
file(STRINGS "${ASCIIDOC}" ASCIIDOC_SHEBANG LIMIT_COUNT 1)
if(ASCIIDOC_SHEBANG MATCHES "/sh|/bash" OR MINGW)
if(ASCIIDOC_SHEBANG MATCHES "sh$" OR MINGW)
set(ASCIIDOC_PY_FOUND ON)
# Run the program directly and set ASCIIDOC as empty.
set(ASCIIDOC_PY "${ASCIIDOC}")
Expand Down
16 changes: 8 additions & 8 deletions lib/cms/color_encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ typedef enum {
JXL_COLOR_SPACE_UNKNOWN,
} JxlColorSpace;

/** Built-in whitepoints for color encoding. When decoding, the numerical xy
* whitepoint value can be read from the @ref JxlColorEncoding white_point field
* regardless of the enum value. When encoding, enum values except
* JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values
/** Built-in white points for color encoding. When decoding, the numerical xy
* white point value can be read from the @ref JxlColorEncoding white_point
* field regardless of the enum value. When encoding, enum values except
* ::JXL_WHITE_POINT_CUSTOM override the numerical fields. Some enum values
* match a subset of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)), however
* the white point and RGB primaries are separate enums here.
*/
Expand Down Expand Up @@ -72,7 +72,7 @@ typedef enum {
* of CICP (Rec. ITU-T H.273 | ISO/IEC 23091-2:2019(E)) unless specified
* otherwise. */
typedef enum {
/** As specified in SMPTE RP 431-2 */
/** As specified in ITU-R BT.709-6 */
JXL_TRANSFER_FUNCTION_709 = 1,
/** None of the other table entries describe the transfer function. */
JXL_TRANSFER_FUNCTION_UNKNOWN = 2,
Expand All @@ -91,7 +91,7 @@ typedef enum {
JXL_TRANSFER_FUNCTION_GAMMA = 65535,
} JxlTransferFunction;

/** Renderig intent for color encoding, as specified in ISO 15076-1:2010 */
/** Rendering intent for color encoding, as specified in ISO 15076-1:2010 */
typedef enum {
/** vendor-specific */
JXL_RENDERING_INTENT_PERCEPTUAL = 0,
Expand All @@ -110,8 +110,8 @@ typedef struct {
*/
JxlColorSpace color_space;

/** Built-in white point. If this value is JXL_WHITE_POINT_CUSTOM, must
* use the numerical whitepoint values from white_point_xy.
/** Built-in white point. If this value is ::JXL_WHITE_POINT_CUSTOM, must
* use the numerical white point values from white_point_xy.
*/
JxlWhitePoint white_point;

Expand Down
2 changes: 1 addition & 1 deletion lib/cms/color_encoding_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ struct ColorEncoding {
}

// Sets the raw ICC profile bytes, without parsing the ICC, and without
// updating the direct fields such as whitepoint, primaries and color
// updating the direct fields such as white point, primaries and color
// space. Functions to get and set fields, such as SetWhitePoint, cannot be
// used anymore after this and functions such as IsSRGB return false no matter
// what the contents of the icc profile.
Expand Down
4 changes: 2 additions & 2 deletions lib/cms/jxl_cms_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ constexpr Matrix3x3 kBradfordInv{{{0.9869929f, -0.1470543f, 0.1599627f},
{0.4323053f, 0.5183603f, 0.0492912f},
{-0.0085287f, 0.0400428f, 0.9684867f}}};

// Adapts whitepoint x, y to D50
// Adapts white point x, y to D50
static Status AdaptToXYZD50(float wx, float wy, Matrix3x3& matrix) {
bool ok = (wx >= 0) && (wx <= 1) && (wy > 0) && (wy <= 1);
if (!ok) {
Expand Down Expand Up @@ -359,7 +359,7 @@ static Status CreateICCChadMatrix(double wx, double wy, Matrix3x3& result) {
return true;
}

// Creates RGB to XYZ matrix given RGB primaries and whitepoint in xy.
// Creates RGB to XYZ matrix given RGB primaries and white point in xy.
static Status CreateICCRGBMatrix(double rx, double ry, double gx, double gy,
double bx, double by, double wx, double wy,
Matrix3x3& result) {
Expand Down
36 changes: 12 additions & 24 deletions lib/cms/transfer_functions-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,14 @@ class TF_SRGB {
// TODO(janwas): range reduction
// Computed via af_cheb_rational (k=100); replicated 4x.
HWY_ALIGN constexpr float p[(4 + 1) * 4] = {
2.200248328e-04f, 2.200248328e-04f, 2.200248328e-04f, 2.200248328e-04f,
1.043637593e-02f, 1.043637593e-02f, 1.043637593e-02f, 1.043637593e-02f,
1.624820318e-01f, 1.624820318e-01f, 1.624820318e-01f, 1.624820318e-01f,
7.961564959e-01f, 7.961564959e-01f, 7.961564959e-01f, 7.961564959e-01f,
8.210152774e-01f, 8.210152774e-01f, 8.210152774e-01f, 8.210152774e-01f,
HWY_REP4(2.200248328e-04f), HWY_REP4(1.043637593e-02f),
HWY_REP4(1.624820318e-01f), HWY_REP4(7.961564959e-01f),
HWY_REP4(8.210152774e-01f),
};
HWY_ALIGN constexpr float q[(4 + 1) * 4] = {
2.631846970e-01f, 2.631846970e-01f, 2.631846970e-01f,
2.631846970e-01f, 1.076976492e+00f, 1.076976492e+00f,
1.076976492e+00f, 1.076976492e+00f, 4.987528350e-01f,
4.987528350e-01f, 4.987528350e-01f, 4.987528350e-01f,
-5.512498495e-02f, -5.512498495e-02f, -5.512498495e-02f,
-5.512498495e-02f, 6.521209011e-03f, 6.521209011e-03f,
6.521209011e-03f, 6.521209011e-03f,
HWY_REP4(2.631846970e-01f), HWY_REP4(1.076976492e+00f),
HWY_REP4(4.987528350e-01f), HWY_REP4(-5.512498495e-02f),
HWY_REP4(6.521209011e-03f),
};
const V linear = Mul(x, Set(d, kLowDivInv));
const V poly = EvalRationalPolynomial(d, x, p, q);
Expand All @@ -232,20 +226,14 @@ class TF_SRGB {

// Computed via af_cheb_rational (k=100); replicated 4x.
HWY_ALIGN constexpr float p[(4 + 1) * 4] = {
-5.135152395e-04f, -5.135152395e-04f, -5.135152395e-04f,
-5.135152395e-04f, 5.287254571e-03f, 5.287254571e-03f,
5.287254571e-03f, 5.287254571e-03f, 3.903842876e-01f,
3.903842876e-01f, 3.903842876e-01f, 3.903842876e-01f,
1.474205315e+00f, 1.474205315e+00f, 1.474205315e+00f,
1.474205315e+00f, 7.352629620e-01f, 7.352629620e-01f,
7.352629620e-01f, 7.352629620e-01f,
HWY_REP4(-5.135152395e-04f), HWY_REP4(5.287254571e-03f),
HWY_REP4(3.903842876e-01f), HWY_REP4(1.474205315e+00f),
HWY_REP4(7.352629620e-01f),
};
HWY_ALIGN constexpr float q[(4 + 1) * 4] = {
1.004519624e-02f, 1.004519624e-02f, 1.004519624e-02f, 1.004519624e-02f,
3.036675394e-01f, 3.036675394e-01f, 3.036675394e-01f, 3.036675394e-01f,
1.340816930e+00f, 1.340816930e+00f, 1.340816930e+00f, 1.340816930e+00f,
9.258482155e-01f, 9.258482155e-01f, 9.258482155e-01f, 9.258482155e-01f,
2.424867759e-02f, 2.424867759e-02f, 2.424867759e-02f, 2.424867759e-02f,
HWY_REP4(1.004519624e-02f), HWY_REP4(3.036675394e-01f),
HWY_REP4(1.340816930e+00f), HWY_REP4(9.258482155e-01f),
HWY_REP4(2.424867759e-02f),
};
const V linear = Mul(x, Set(d, kLowDiv));
const V poly = EvalRationalPolynomial(d, Sqrt(x), p, q);
Expand Down
2 changes: 1 addition & 1 deletion lib/cms/transfer_functions_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ HWY_NOINLINE void TestPqEncodedFromDisplay() {
const float actual = GetLane(tf_pq.EncodedFromDisplay(d, Set(d, f)));
const float expected = TF_PQ_Base::EncodedFromDisplay(intensity, f);
const float abs_err = std::abs(expected - actual);
EXPECT_LT(abs_err, 5e-7) << "f = " << f;
EXPECT_LT(abs_err, 6e-7) << "f = " << f;
max_abs_err = std::max(max_abs_err, abs_err);
}
printf("max abs err %e\n", static_cast<double>(max_abs_err));
Expand Down
4 changes: 3 additions & 1 deletion lib/extras/dec/jpegli.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ Status DecodeJpeg(const std::vector<uint8_t>& compressed,
}
int nbcomp = cinfo.num_components;
if (nbcomp != 1 && nbcomp != 3) {
return failure("unsupported number of components in JPEG");
std::string msg =
"unsupported number of components in JPEG: " + std::to_string(nbcomp);
return failure(msg.c_str());
}
if (dparams.force_rgb) {
cinfo.out_color_space = JCS_RGB;
Expand Down
7 changes: 7 additions & 0 deletions tools/benchmark/benchmark_args.cc
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ Status BenchmarkArgs::AddCommandLineOptions() {
"Distance numbers and compression speeds shown in the table are invalid.",
false);

AddUnsigned(
&generations, "generations",
"If nonzero, enables generation loss testing with this number of "
"intermediate generations. "
"That is, the decoded image gets re-encoded, iteratively, N times.",
0);

if (!AddCommandLineOptionsJPEGCodec(this)) return false;

return true;
Expand Down
1 change: 1 addition & 0 deletions tools/benchmark/benchmark_args.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ struct BenchmarkArgs {
int inner_threads;
size_t decode_reps;
size_t encode_reps;
size_t generations;

double error_pnorm;
bool show_progress;
Expand Down
108 changes: 60 additions & 48 deletions tools/benchmark/benchmark_xl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,64 +139,65 @@ void DoCompress(const std::string& filename, const PackedPixelFile& ppf,
// this function to indicate it as error in the stats.
valid = false;
}
const PackedPixelFile* ppf1 = &ppf;
PackedPixelFile ppf2;

std::string ext = FileExtension(filename);
if (valid && !Args()->decode_only) {
for (size_t i = 0; i < Args()->encode_reps; ++i) {
if (codec->CanRecompressJpeg() && (ext == ".jpg" || ext == ".jpeg")) {
std::vector<uint8_t> data_in;
JXL_CHECK(ReadFile(filename, &data_in));
JXL_CHECK(
codec->RecompressJpeg(filename, data_in, compressed, &speed_stats));
} else {
Status status = codec->Compress(filename, ppf, inner_pool, compressed,
&speed_stats);
if (!status) {
valid = false;
if (!Args()->silent_errors) {
std::string message = codec->GetErrorMessage();
if (!message.empty()) {
fprintf(stderr, "Error in %s codec: %s\n",
codec->description().c_str(), message.c_str());
} else {
fprintf(stderr, "Error in %s codec\n",
codec->description().c_str());
for (size_t generation = 0; generation <= Args()->generations; generation++) {
std::string ext = FileExtension(filename);
if (valid && !Args()->decode_only) {
for (size_t i = 0; i < Args()->encode_reps; ++i) {
if (codec->CanRecompressJpeg() && (ext == ".jpg" || ext == ".jpeg")) {
std::vector<uint8_t> data_in;
JXL_CHECK(ReadFile(filename, &data_in));
JXL_CHECK(codec->RecompressJpeg(filename, data_in, compressed,
&speed_stats));
} else {
Status status = codec->Compress(filename, *ppf1, inner_pool,
compressed, &speed_stats);
if (!status) {
valid = false;
if (!Args()->silent_errors) {
std::string message = codec->GetErrorMessage();
if (!message.empty()) {
fprintf(stderr, "Error in %s codec: %s\n",
codec->description().c_str(), message.c_str());
} else {
fprintf(stderr, "Error in %s codec\n",
codec->description().c_str());
}
}
}
}
}
JXL_CHECK(speed_stats.GetSummary(&summary));
s->total_time_encode += summary.central_tendency;
}
JXL_CHECK(speed_stats.GetSummary(&summary));
s->total_time_encode += summary.central_tendency;
}

if (valid && Args()->decode_only) {
std::vector<uint8_t> data_in;
JXL_CHECK(ReadFile(filename, &data_in));
compressed->insert(compressed->end(), data_in.begin(), data_in.end());
}
if (valid && Args()->decode_only) {
std::vector<uint8_t> data_in;
JXL_CHECK(ReadFile(filename, &data_in));
compressed->insert(compressed->end(), data_in.begin(), data_in.end());
}

// Decompress
PackedPixelFile ppf2;
if (valid) {
speed_stats = jpegxl::tools::SpeedStats();
for (size_t i = 0; i < Args()->decode_reps; ++i) {
if (!codec->Decompress(filename, Bytes(*compressed), inner_pool, &ppf2,
&speed_stats)) {
if (!Args()->silent_errors) {
fprintf(stderr,
"%s failed to decompress encoded image. Original source:"
" %s\n",
codec->description().c_str(), filename.c_str());
// Decompress
if (valid) {
speed_stats = jpegxl::tools::SpeedStats();
for (size_t i = 0; i < Args()->decode_reps; ++i) {
if (!codec->Decompress(filename, Bytes(*compressed), inner_pool, &ppf2,
&speed_stats)) {
if (!Args()->silent_errors) {
fprintf(stderr,
"%s failed to decompress encoded image. Original source:"
" %s\n",
codec->description().c_str(), filename.c_str());
}
valid = false;
}
valid = false;
}
JXL_CHECK(speed_stats.GetSummary(&summary));
s->total_time_decode += summary.central_tendency;
}
for (const auto& frame : ppf2.frames) {
s->total_input_pixels += frame.color.xsize * frame.color.ysize;
}
JXL_CHECK(speed_stats.GetSummary(&summary));
s->total_time_decode += summary.central_tendency;
ppf1 = &ppf2;
}

std::string name = FileBaseName(filename);
Expand All @@ -206,6 +207,12 @@ void DoCompress(const std::string& filename, const PackedPixelFile& ppf,
s->total_errors++;
}

if (valid) {
for (const auto& frame : ppf2.frames) {
s->total_input_pixels += frame.color.xsize * frame.color.ysize;
}
}

if (ppf.frames.size() != ppf2.frames.size()) {
if (!Args()->silent_errors) {
// Animated gifs not supported yet?
Expand Down Expand Up @@ -775,7 +782,12 @@ class Benchmark {
std::unique_ptr<ThreadPoolInternal> pool;
std::vector<std::unique_ptr<ThreadPoolInternal>> inner_pools;
InitThreads(tasks.size(), &pool, &inner_pools);

if (Args()->generations > 0) {
fprintf(stderr,
"Generation loss testing with %" PRIuS
" intermediate generations\n",
Args()->generations);
}
std::vector<PackedPixelFile> loaded_images =
LoadImages(fnames, pool->get());

Expand Down
Loading