blob: 5e38b22a6cdd237f91d7ae7fec6112ab79b7d4f6 [file] [log] [blame]
// Copyright (c) the JPEG XL Project
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <tuple>
#include "imageio/image_dec.h"
#include "src/dec/lossless/losslessi_dec.h"
#include "src/enc/lossless/losslessi_enc.h"
#include "src/utils/utils.h"
#include "src/utils/vector.h"
#include "src/wp2/base.h"
#include "src/wp2/decode.h"
#include "src/wp2/encode.h"
#include "src/wp2/format_constants.h"
#include "tests/include/helpers.h"
namespace WP2 {
namespace {
// Limit makes it choose fewer values so per-channel palette will be used
WP2::ArgbBuffer GenerateImage(size_t xsize, size_t ysize, bool has_alpha,
bool limit[4]) {
WP2::ArgbBuffer image(WP2_ARGB_32);
EXPECT_EQ(image.Resize(xsize, ysize), WP2_STATUS_OK);
for (size_t y = 0; y < ysize; ++y) {
auto* row = image.GetRow8(y);
for (size_t x = 0; x < xsize; ++x) {
row[4 * x + 0] = has_alpha ? x + y : 255;
if (limit[0]) row[4 * x + 0] &= ~3u;
for (int c = 1; c < 4; c++) {
auto* ptr = &row[4 * x + c];
*ptr = x + y * c;
if (limit[c]) *ptr &= ~3u;
}
}
}
return image;
}
// Limit makes it choose fewer values so per-channel palette will be used
void TestRoundTrip(const WP2::ArgbBuffer& image,
WP2L::EncodingAlgorithm algorithm) {
WP2::Vector_u8 bytes;
MemoryWriter memory_writer;
EncoderConfig encoder_config;
encoder_config.quality = 100;
encoder_config.keep_unmultiplied = true;
encoder_config.lossless_algorithm = algorithm;
WP2_ASSERT_STATUS(Encode(image, &memory_writer, encoder_config));
DecoderConfig decoder_config;
ArgbBuffer decompressed(WP2_ARGB_32);
WP2_ASSERT_STATUS(Decode(memory_writer.mem_, memory_writer.size_,
&decompressed, decoder_config));
EXPECT_TRUE(testutil::Compare(image, decompressed, /*file_name=*/"pattern"));
}
class LosslessTestGen
: public testing::TestWithParam<
std::tuple<int, bool, std::array<int, 2>, WP2L::EncodingAlgorithm>> {
};
TEST_P(LosslessTestGen, RoundTripData) {
const size_t val = std::get<0>(GetParam());
const bool has_alpha = std::get<1>(GetParam());
const size_t xsize = std::get<2>(GetParam())[0];
const size_t ysize = std::get<2>(GetParam())[1];
const WP2L::EncodingAlgorithm algorithm = std::get<3>(GetParam());
bool limit[4] = {false};
for (int i = 0; i < 4; ++i) limit[i] = static_cast<bool>(val & (1 << i));
const auto image = GenerateImage(xsize, ysize, has_alpha, limit);
TestRoundTrip(image, algorithm);
}
INSTANTIATE_TEST_SUITE_P(
LosslessTestInstantiation, LosslessTestGen,
testing::Combine(testing::Range(0, 1), testing::Values(false, true),
testing::Values(std::array<int, 2>{1, 1},
std::array<int, 2>{3, 5},
std::array<int, 2>{16, 16},
std::array<int, 2>{256, 256},
std::array<int, 2>{5, 800}),
testing::Values(WP2L::EncodingAlgorithm::kSCP,
WP2L::EncodingAlgorithm::kCALIC)));
class LosslessTestFile : public testing::TestWithParam<
std::tuple<std::string, WP2L::EncodingAlgorithm>> {
};
TEST_P(LosslessTestFile, RoundTripFile) {
const std::string file = std::get<0>(GetParam());
const WP2L::EncodingAlgorithm algorithm = std::get<1>(GetParam());
WP2::ArgbBuffer image(WP2_ARGB_32);
ASSERT_EQ(WP2::ReadImage(testutil::GetTestDataPath(file).c_str(), &image),
WP2_STATUS_OK)
<< testutil::GetTestDataPath(file);
TestRoundTrip(image, algorithm);
}
INSTANTIATE_TEST_SUITE_P(
LosslessTestInstantiation, LosslessTestFile,
testing::Combine(testing::Values("background.png", "logo.png",
"source1_64x48.png"),
testing::Values(WP2L::EncodingAlgorithm::kSCP,
WP2L::EncodingAlgorithm::kCALIC)));
////////////////////////////////////////////////////////////////////////////////
TEST(Distance, Roundtrip) {
constexpr int16_t kMin = -10, kMax = -10;
for (bool use_opposite_error : {false, true}) {
for (int16_t v = kMin; v <= kMax; ++v) {
for (int16_t p = kMin; p <= kMax; ++p) {
const int16_t d = WP2L::CalcDistanceFromPredictionAndTPV(
p, use_opposite_error, v, kMin, kMax);
const int16_t v_predicted = WP2L::CalcTPVFromPredictionAndDistance(
p, use_opposite_error, d, kMin, kMax);
EXPECT_EQ(v, v_predicted);
}
}
}
}
} // namespace
} // namespace WP2