blob: 687b6c0fb8030b8bfdce6c89a1e9e79c48232aa2 [file] [log] [blame]
// Copyright 2020 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
//
// http://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.
// Test Group4 lossless algorithm for binary images.
#include <algorithm>
#include <cstdint>
#include <string>
#include <tuple>
#include <vector>
#include "src/common/color_precision.h"
#include "src/utils/random.h"
#include "src/utils/utils.h"
#include "src/wp2/base.h"
#include "src/wp2/decode.h"
#include "src/wp2/encode.h"
#include "src/wp2/format_constants.h"
#include "gtest/gtest.h"
#include "tests/include/helpers.h"
namespace WP2 {
namespace {
static std::string DisplayMask(int dim, const ArgbBuffer &image) {
std::string out = "****\n";
std::vector<uint32_t> colors;
for (int y = 0; y < dim; ++y) {
const auto row = (const uint32_t *)image.GetRow(y);
for (int x = 0; x < dim; ++x) {
uint32_t i = 0;
while (i < colors.size() && colors[i] != row[x]) ++i;
if (i == colors.size()) colors.push_back(row[x]);
out.append(std::to_string(i));
}
out.append("\n");
}
out.append("\n");
return out;
}
//------------------------------------------------------------------------------
enum class Type { kCircle, kRandom };
class Group4Test : public testing::TestWithParam<std::tuple<Type, int, int>> {};
static void RandomColor(UniformIntDistribution *const gen, uint8_t color[4]) {
for (uint32_t c = 0; c < 4; ++c) {
if (c == 0 && gen->FlipACoin()) {
color[c] = WP2::kAlphaMax;
} else {
color[c] = gen->Get(0u, (c == 0) ? WP2::kAlphaMax : color[0]);
}
}
}
TEST_P(Group4Test, Pattern) {
const Type type = std::get<0>(GetParam());
const uint32_t seed = std::get<1>(GetParam());
const int dim = std::get<2>(GetParam());
WP2::UniformIntDistribution gen(seed);
ArgbBuffer original;
ASSERT_EQ(original.Resize(dim, dim), WP2_STATUS_OK);
// Draw a pattern.
if (type == Type::kRandom) {
// Choose two colors.
uint8_t colors[2][4];
for (uint32_t i = 0; i < 2; ++i) {
RandomColor(&gen, colors[i]);
}
for (int y = 0; y < dim; ++y) {
uint8_t *const row = (uint8_t *)original.GetRow(y);
for (int x = 0; x < dim; ++x) {
const uint32_t color_index = gen.FlipACoin();
std::copy(colors[color_index], colors[color_index] + 4, &row[4 * x]);
}
}
} else {
uint8_t color[4];
RandomColor(&gen, color);
original.Fill(WP2::ToArgb32b(color));
const uint32_t num_circles = gen.Get(1, dim / 10 + 1);
for (uint32_t i = 1; i < num_circles; ++i) {
const int center_x = gen.Get(0, dim - 1);
const int center_y = gen.Get(0, dim - 1);
const int radius = gen.Get(0, dim);
RandomColor(&gen, color);
for (int y = 0; y < dim; ++y) {
uint8_t *const row = (uint8_t *)original.GetRow(y);
for (int x = 0; x < dim; ++x) {
if ((x - center_x) * (x - center_x) +
(y - center_y) * (y - center_y) <
radius * radius) {
std::copy(color, color + 4, &row[4 * x]);
}
}
}
}
}
MemoryWriter memory_writer;
EncoderConfig encoder_config;
encoder_config.quality = 100;
encoder_config.lossless_algorithm = WP2L::EncodingAlgorithm::kGroup4;
WP2_ASSERT_STATUS(Encode(original, &memory_writer, encoder_config));
DecoderConfig decoder_config;
ArgbBuffer decompressed;
WP2_ASSERT_STATUS(Decode(memory_writer.mem_, memory_writer.size_,
&decompressed, decoder_config));
EXPECT_TRUE(
testutil::Compare(original, decompressed, /*file_name=*/"pattern"))
<< DisplayMask(dim, original) << DisplayMask(dim, decompressed);
} // namespace
INSTANTIATE_TEST_SUITE_P(
Group4Test, Group4Test,
testing::Combine(testing::Values(Type::kCircle, Type::kRandom), // type
testing::Range(0, 20), // seed
testing::Values(WP2L::kGroup4Window, 101) // dim
));
} // namespace
} // namespace WP2