imagediff.h (6659B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See blend2d.h or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 // This file provides utility classes and functions shared between some tests. 7 8 #ifndef TESTING_IMAGEDIFF_H_INCLUDED 9 #define TESTING_IMAGEDIFF_H_INCLUDED 10 11 #include <blend2d.h> 12 #include <stdint.h> 13 14 namespace ImageUtils { 15 16 struct DiffInfo { 17 uint32_t max_diff; 18 uint64_t cumulative_diff; 19 }; 20 21 [[maybe_unused]] 22 static DiffInfo diff_info(const BLImage& a_image, const BLImage& b_image) noexcept { 23 DiffInfo info {}; 24 BLImageData a_data; 25 BLImageData b_data; 26 27 // Used in case of error (image size/format doesn't match). 28 info.max_diff = 0xFFFFFFFFu; 29 30 if (a_image.size() != b_image.size()) 31 return info; 32 33 size_t w = size_t(a_image.width()); 34 size_t h = size_t(a_image.height()); 35 36 if (a_image.get_data(&a_data) != BL_SUCCESS) 37 return info; 38 39 if (b_image.get_data(&b_data) != BL_SUCCESS) 40 return info; 41 42 if (a_data.format != b_data.format) { 43 if ((a_data.format == BL_FORMAT_XRGB32 && b_data.format == BL_FORMAT_PRGB32) || 44 (a_data.format == BL_FORMAT_PRGB32 && b_data.format == BL_FORMAT_XRGB32)) { 45 // Pass: We would convert between these two formats on the fly. 46 } 47 else { 48 return info; 49 } 50 } 51 52 intptr_t a_stride = a_data.stride; 53 intptr_t b_stride = b_data.stride; 54 55 const uint8_t* a_line = static_cast<const uint8_t*>(a_data.pixel_data); 56 const uint8_t* b_line = static_cast<const uint8_t*>(b_data.pixel_data); 57 58 info.max_diff = 0; 59 60 switch (a_data.format) { 61 case BL_FORMAT_XRGB32: 62 case BL_FORMAT_PRGB32: { 63 uint32_t a_mask = a_data.format == BL_FORMAT_XRGB32 ? 0xFF000000u : 0x0u; 64 uint32_t b_mask = b_data.format == BL_FORMAT_XRGB32 ? 0xFF000000u : 0x0u; 65 66 for (size_t y = 0; y < h; y++) { 67 const uint32_t* a_ptr = reinterpret_cast<const uint32_t*>(a_line); 68 const uint32_t* b_ptr = reinterpret_cast<const uint32_t*>(b_line); 69 70 for (size_t x = 0; x < w; x++) { 71 uint32_t a_val = a_ptr[x] | a_mask; 72 uint32_t b_val = b_ptr[x] | b_mask; 73 74 if (a_val != b_val) { 75 uint32_t a_diff = uint32_t(bl_abs(int((a_val >> 24) & 0xFF) - int((b_val >> 24) & 0xFF))); 76 uint32_t r_diff = uint32_t(bl_abs(int((a_val >> 16) & 0xFF) - int((b_val >> 16) & 0xFF))); 77 uint32_t gDiff = uint32_t(bl_abs(int((a_val >> 8) & 0xFF) - int((b_val >> 8) & 0xFF))); 78 uint32_t b_diff = uint32_t(bl_abs(int((a_val ) & 0xFF) - int((b_val ) & 0xFF))); 79 uint32_t max_diff = bl_max(a_diff, r_diff, gDiff, b_diff); 80 81 info.max_diff = bl_max(info.max_diff, max_diff); 82 info.cumulative_diff += max_diff; 83 } 84 } 85 86 a_line += a_stride; 87 b_line += b_stride; 88 } 89 break; 90 } 91 92 case BL_FORMAT_A8: { 93 for (size_t y = 0; y < h; y++) { 94 const uint8_t* a_ptr = a_line; 95 const uint8_t* b_ptr = b_line; 96 97 for (size_t x = 0; x < w; x++) { 98 uint32_t a_val = a_ptr[x]; 99 uint32_t b_val = b_ptr[x]; 100 uint32_t diff = uint32_t(bl_abs(int(a_val) - int(b_val))); 101 102 info.max_diff = bl_max(info.max_diff, diff); 103 info.cumulative_diff += diff; 104 } 105 106 a_line += a_stride; 107 b_line += b_stride; 108 } 109 break; 110 } 111 112 default: { 113 info.max_diff = 0xFFFFFFFFu; 114 break; 115 } 116 } 117 118 return info; 119 } 120 121 [[maybe_unused]] 122 static BLImage diff_image(const BLImage& a_image, const BLImage& b_image) noexcept { 123 BLImage result; 124 BLImageData r_data; 125 BLImageData a_data; 126 BLImageData b_data; 127 128 if (a_image.size() != b_image.size()) 129 return result; 130 131 size_t w = size_t(a_image.width()); 132 size_t h = size_t(a_image.height()); 133 134 if (a_image.get_data(&a_data) != BL_SUCCESS) 135 return result; 136 137 if (b_image.get_data(&b_data) != BL_SUCCESS) 138 return result; 139 140 if (a_data.format != b_data.format) 141 return result; 142 143 if (result.create(int(w), int(h), BL_FORMAT_XRGB32) != BL_SUCCESS) 144 return result; 145 146 if (result.get_data(&r_data) != BL_SUCCESS) 147 return result; 148 149 intptr_t d_stride = r_data.stride; 150 intptr_t a_stride = a_data.stride; 151 intptr_t b_stride = b_data.stride; 152 153 uint8_t* d_line = static_cast<uint8_t*>(r_data.pixel_data); 154 const uint8_t* a_line = static_cast<const uint8_t*>(a_data.pixel_data); 155 const uint8_t* b_line = static_cast<const uint8_t*>(b_data.pixel_data); 156 157 auto&& color_from_diff = [](uint32_t diff) noexcept -> uint32_t { 158 static constexpr uint32_t low_diff[] = { 159 0xFF000000u, 160 0xFF0000A0u, 161 0xFF0000C0u, 162 0xFF0000FFu, 163 0xFF0040A0u 164 }; 165 166 if (diff <= 4u) 167 return low_diff[diff]; 168 else if (diff <= 16u) 169 return 0xFF000000u + unsigned((diff * 16u - 1u) << 8); 170 else 171 return 0xFF000000u + unsigned((127u + diff / 2u) << 16); 172 }; 173 174 switch (a_data.format) { 175 case BL_FORMAT_PRGB32: 176 case BL_FORMAT_XRGB32: { 177 for (size_t y = 0; y < h; y++) { 178 uint32_t* d_ptr = reinterpret_cast<uint32_t*>(d_line); 179 const uint32_t* a_ptr = reinterpret_cast<const uint32_t*>(a_line); 180 const uint32_t* b_ptr = reinterpret_cast<const uint32_t*>(b_line); 181 182 for (size_t x = 0; x < w; x++) { 183 uint32_t a_val = a_ptr[x]; 184 uint32_t b_val = b_ptr[x]; 185 uint32_t diff = uint32_t(bl_abs(int(a_val) - int(b_val))); 186 187 uint32_t color = color_from_diff(diff); 188 d_ptr[x] = color; 189 } 190 191 d_line += d_stride; 192 a_line += a_stride; 193 b_line += b_stride; 194 } 195 break; 196 } 197 198 case BL_FORMAT_A8: { 199 for (size_t y = 0; y < h; y++) { 200 uint32_t* d_ptr = reinterpret_cast<uint32_t*>(d_line); 201 const uint8_t* a_ptr = a_line; 202 const uint8_t* b_ptr = b_line; 203 204 for (size_t x = 0; x < w; x++) { 205 uint32_t a_val = a_ptr[x]; 206 uint32_t b_val = b_ptr[x]; 207 int a_diff = bl_abs(int((a_val >> 24) & 0xFF) - int((b_val >> 24) & 0xFF)); 208 int r_diff = bl_abs(int((a_val >> 16) & 0xFF) - int((b_val >> 16) & 0xFF)); 209 int gDiff = bl_abs(int((a_val >> 8) & 0xFF) - int((b_val >> 8) & 0xFF)); 210 int b_diff = bl_abs(int((a_val ) & 0xFF) - int((b_val ) & 0xFF)); 211 212 uint32_t color = color_from_diff(uint32_t(bl_max(a_diff, r_diff, gDiff, b_diff))); 213 d_ptr[x] = color; 214 } 215 216 d_line += d_stride; 217 a_line += a_stride; 218 b_line += b_stride; 219 } 220 break; 221 } 222 223 default: { 224 result.reset(); 225 break; 226 } 227 } 228 229 return result; 230 } 231 232 } // {ImageUtils} 233 234 #endif // TESTING_IMAGEDIFF_H_INCLUDED