Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ jobs:
sudo apt-get install -y clang-16 libc++-16-dev libc++abi-16-dev
echo "/usr/lib/llvm-16/bin" >> $GITHUB_PATH

- name: Install cmake
run: |
sudo apt-get install -y cmake ninja-build
echo "/usr/bin/cmake" >> $GITHUB_PATH

# Enable tmate debugging of manually-triggered workflows if the input option was provided
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
Expand All @@ -62,3 +67,16 @@ jobs:
- name: Test (C++20)
run: |
"${GITHUB_WORKSPACE}/bin/bazel" test --config=clang --config=cpp20 //...

- name: Build (CMake)
run: |
cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --build build
ctest --test-dir build --output-on-failure

- name: Build w/ Tests (CMake)
run: |
rm -rf build
cmake -S . -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPIXELMATCH_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure
26 changes: 26 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,29 @@ coverage-report
# The Bzlmod lockfile is platform-dependent with Python and thus hard
# to keep up-to-date in CI. It still speeds up local development.
MODULE.bazel.lock

# CMake
# Created by https://www.toptal.com/developers/gitignore/api/cmake
# Edit at https://www.toptal.com/developers/gitignore?templates=cmake

### CMake ###
/build/
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

### CMake Patch ###
CMakeUserPresets.json

# External projects
*-prefix/

# End of https://www.toptal.com/developers/gitignore/api/cmake
50 changes: 50 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.16)
project(pixelmatch-cpp17 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

option(PIXELMATCH_BUILD_TESTS "Enable building tests" OFF)

# stb libraries for tests and image_utils. Not used in pixelmatch-cpp17 itself.
add_library(pixelmatch_third_party_stb_image STATIC third_party/stb/stb_image.cpp)
target_include_directories(pixelmatch_third_party_stb_image PUBLIC third_party)
target_compile_options(pixelmatch_third_party_stb_image PRIVATE -Wno-unused-function -Wno-self-assign)

add_library(pixelmatch_third_party_stb_image_write STATIC third_party/stb/stb_image_write.cpp)
target_include_directories(pixelmatch_third_party_stb_image_write PUBLIC third_party)
target_compile_options(pixelmatch_third_party_stb_image_write PRIVATE -Wno-unused-function -Wno-self-assign)

# Main library
add_library(pixelmatch-cpp17 src/pixelmatch/pixelmatch.cc)
target_include_directories(pixelmatch-cpp17 PUBLIC src)

# image_utils helper library (uses stb to load and save images)
add_library(image_utils src/pixelmatch/image_utils.cc)
target_include_directories(image_utils PUBLIC src)
target_link_libraries(image_utils PUBLIC pixelmatch-cpp17 pixelmatch_third_party_stb_image pixelmatch_third_party_stb_image_write)

if(PIXELMATCH_BUILD_TESTS)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing()
add_library(test_base INTERFACE)
target_link_libraries(test_base INTERFACE GTest::gtest_main GTest::gmock_main m)

add_executable(pixelmatch_tests tests/pixelmatch_tests.cc)
target_link_libraries(pixelmatch_tests PRIVATE test_base pixelmatch-cpp17 image_utils)
add_test(NAME pixelmatch_tests COMMAND pixelmatch_tests)
set_tests_properties(pixelmatch_tests PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})

add_executable(image_utils_tests tests/image_utils_tests.cc)
target_link_libraries(image_utils_tests PRIVATE test_base image_utils)
add_test(NAME image_utils_tests COMMAND image_utils_tests)
set_tests_properties(image_utils_tests PROPERTIES WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})

endif() # PIXELMATCH_BUILD_TESTS
12 changes: 7 additions & 5 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ git_override(

module(name = "pixelmatch-cpp17", repo_name = "pixelmatch-cpp17", version = "1.0.1")

new_local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "new_local_repository")

#
# Build dependencies
#
Expand All @@ -22,11 +24,11 @@ bazel_dep(name = "rules_cc", version = "0.1.1")
# Test dependencies
#
bazel_dep(name = "googletest", repo_name = "com_google_gtest", version = "1.17.0", dev_dependency = True)
bazel_dep(name = "stb", version = "0.0.0", dev_dependency = True)
git_override(
module_name = "stb",
remote = "https://github.com/jwmcglynn/rules_stb",
commit = "075e5a470e31e46a7318cc308c79dba205a6b2eb",

new_local_repository(
name = "stb",
build_file = "//third_party:BUILD.stb",
path = "third_party/stb",
)

#
Expand Down
56 changes: 43 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,28 +73,58 @@ git_override(
)
```

#### Adding the dependency
### CMake

Then add a dependency on `@pixelmatch-cpp17`:
```py
cc_test(
name = "my_test",
# ...
data = glob([
"testdata/*.png",
]),
deps = [
"@pixelmatch-cpp17",
# ...
],
To take a dependency on `pixelmatch-cpp17` with `FetchContent`, add the following
to your project's `CMakeLists.txt`:

```cmake
include(FetchContent)
FetchContent_Declare(
pixelmatch-cpp17
GIT_REPOSITORY https://github.com/jwmcglynn/pixelmatch-cpp17.git
GIT_TAG <commit or tag>
)
FetchContent_MakeAvailable(pixelmatch-cpp17)

target_link_libraries(your_target PRIVATE pixelmatch-cpp17)
```

#### Running the tests


This repository also provides CMake build files. A typical workflow is:

```sh
cmake -S . -B build -DPIXELMATCH_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build
```

### Calling from C++

In your test file, include pixelmatch with:
```cpp
#include <pixelmatch/pixelmatch.h>
```

Then, you can use the `pixelmatch::pixelmatch` function.

```cpp
// Pass an options struct to configure the comparison. If not specified, defaults will be used.
pixelmatch::Options options;
options.threshold = 0.1f;

// Load two images as RGBA-encoded byte arrays. The images must have the same dimensions and stride.
const std::vector<uint8_t> img1 = ...;
const std::vector<uint8_t> img2 = ...;
// Output image will be saved in this buffer.
std::vector<uint8_t> diffImage(img1.size());

// Pass the image buffers and call with the width, height, and stride of the images.
const int numDiffPixels = pixelmatch::pixelmatch(img1, img2, diffImage, width, height, stride, options);
```

## Projects using pixelmatch-cpp17

- Python bindings: https://github.com/cubao/pybind11_pixelmatch
Expand Down
1 change: 1 addition & 0 deletions tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ cc_fuzz_test(
srcs = ["pixelmatch_fuzzer.cc"],
linkopts = ["-lm"],
tags = [
"manual",
"nocoverage",
],
deps = [
Expand Down
6 changes: 6 additions & 0 deletions third_party/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports_files(
# buildifier: keep sorted
[
"BUILD.stb",
],
)
161 changes: 161 additions & 0 deletions third_party/BUILD.stb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
load("@pixelmatch-cpp17//third_party:stb.bzl", "stb_library")

STB_COPTS = [
"-Wno-unused-function",
"-Wno-self-assign",
]

stb_library(
name = "c_lexer",
copts = STB_COPTS,
emit_definition_macro = "STB_C_LEXER_IMPLEMENTATION",
)

#
# Note that this needs to be instantiated by following the instructions in stb_connected_components.h
#
# In one source file, create the implementation by doing something like this:
#
# #define STBCC_GRID_COUNT_X_LOG2 10
# #define STBCC_GRID_COUNT_Y_LOG2 10
# #define STB_CONNECTED_COMPONENTS_IMPLEMENTATION
# #include "stb_connected_components.h"
#
stb_library(
name = "connected_components",
copts = STB_COPTS,
)

stb_library(
name = "divide",
copts = STB_COPTS,
emit_definition_macro = "STB_DIVIDE_IMPLEMENTATION",
)

stb_library(
name = "ds",
copts = STB_COPTS,
emit_definition_macro = "STB_DS_IMPLEMENTATION",
)

stb_library(
name = "dxt",
copts = STB_COPTS,
definition_includes = ["memory.h"],
emit_definition_macro = "STB_DXT_IMPLEMENTATION",
)

stb_library(
name = "easy_font",
copts = STB_COPTS,
emit_definition_macro = "STB_EASY_FONT_IMPLEMENTATION",
)

stb_library(
name = "herringbone_wang_tile",
copts = STB_COPTS,
emit_definition_macro = "STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION",
)

stb_library(
name = "hexwave",
copts = STB_COPTS,
emit_definition_macro = "STB_HEXWAVE_IMPLEMENTATION",
)

stb_library(
name = "image",
copts = STB_COPTS,
emit_definition_macro = "STB_IMAGE_IMPLEMENTATION",
)

stb_library(
name = "image_resize2",
copts = STB_COPTS,
emit_definition_macro = "STB_IMAGE_RESIZE_IMPLEMENTATION",
)

stb_library(
name = "image_write",
copts = STB_COPTS,
emit_definition_macro = "STB_IMAGE_WRITE_IMPLEMENTATION",
)

stb_library(
name = "include",
copts = STB_COPTS,
emit_definition_macro = "STB_INCLUDE_IMPLEMENTATION",
)

stb_library(
name = "leakcheck",
copts = STB_COPTS,
emit_definition_macro = "STB_LEAKCHECK_IMPLEMENTATION",
)

stb_library(
name = "perlin",
copts = STB_COPTS,
emit_definition_macro = "STB_PERLIN_IMPLEMENTATION",
)

stb_library(
name = "rect_pack",
copts = STB_COPTS,
emit_definition_macro = "STB_RECT_PACK_IMPLEMENTATION",
)

stb_library(
name = "sprintf",
copts = STB_COPTS,
emit_definition_macro = "STB_SPRINTF_IMPLEMENTATION",
)

stb_library(
name = "textedit",
copts = STB_COPTS,
emit_definition_macro = "STB_TRUETYPE_IMPLEMENTATION",
)

stb_library(
name = "tilemap_editor",
copts = STB_COPTS,
emit_definition_macro = "STB_TRUETYPE_IMPLEMENTATION",
)

stb_library(
name = "truetype",
copts = STB_COPTS,
emit_definition_macro = "STB_TRUETYPE_IMPLEMENTATION",
)

stb_library(
name = "stretchy_buffer",
stb_prefix = False,
)

# stb_vorbis has a reversed mechanism
genrule(
name = "vorbis_definition",
outs = ["stb_vorbis.cpp"],
cmd = 'echo "#include <stb/{0}>" > $(@D)/{1}'.format(
"stb_vorbis.c",
"stb_vorbis.cpp",
),
visibility = ["//visibility:private"],
)

cc_library(
name = "vorbis-private",
srcs = ["stb_vorbis.c"],
copts = STB_COPTS + ["-Wno-unused-value"],
include_prefix = "stb",
visibility = ["//visibility:private"],
)

cc_library(
name = "vorbis",
defines = ["STB_VORBIS_HEADER_ONLY"],
visibility = ["//visibility:public"],
deps = ["//:vorbis-private"],
)
Loading