odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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