// Clip Library
// Copyright (C) 2020-2024 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifndef CLIP_COMMON_H_INCLUDED
#define CLIP_COMMON_H_INCLUDED
#pragma once

namespace clip {
namespace details {

#if CLIP_ENABLE_IMAGE

inline void divide_rgb_by_alpha(image& img,
                                bool hasAlphaGreaterThanZero = false) {
  const image_spec& spec = img.spec();

  bool hasValidPremultipliedAlpha = true;

  for (unsigned long y=0; y<spec.height; ++y) {
    const uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
    for (unsigned long x=0; x<spec.width; ++x, ++dst) {
      const uint32_t c = *dst;
      const int r = ((c & spec.red_mask  ) >> spec.red_shift  );
      const int g = ((c & spec.green_mask) >> spec.green_shift);
      const int b = ((c & spec.blue_mask ) >> spec.blue_shift );
      const int a = ((c & spec.alpha_mask) >> spec.alpha_shift);

      if (a > 0)
        hasAlphaGreaterThanZero = true;
      if (r > a || g > a || b > a)
        hasValidPremultipliedAlpha = false;
    }
  }

  for (unsigned long y=0; y<spec.height; ++y) {
    uint32_t* dst = (uint32_t*)(img.data()+y*spec.bytes_per_row);
    for (unsigned long x=0; x<spec.width; ++x, ++dst) {
      const uint32_t c = *dst;
      int r = ((c & spec.red_mask  ) >> spec.red_shift  );
      int g = ((c & spec.green_mask) >> spec.green_shift);
      int b = ((c & spec.blue_mask ) >> spec.blue_shift );
      int a = ((c & spec.alpha_mask) >> spec.alpha_shift);

      // If all alpha values = 0, we make the image opaque.
      if (!hasAlphaGreaterThanZero) {
        a = 255;

        // We cannot change the image spec (e.g. spec.alpha_mask=0) to
        // make the image opaque, because the "spec" of the image is
        // read-only. The image spec used by the client is the one
        // returned by get_image_spec().
      }
      // If there is alpha information and it's pre-multiplied alpha
      else if (hasValidPremultipliedAlpha) {
        if (a > 0) {
          // Convert it to straight alpha
          r = r * 255 / a;
          g = g * 255 / a;
          b = b * 255 / a;
        }
      }

      *dst =
        (r << spec.red_shift  ) |
        (g << spec.green_shift) |
        (b << spec.blue_shift ) |
        (a << spec.alpha_shift);
    }
  }
}

#endif // CLIP_ENABLE_IMAGE

} // namespace details
} // namespace clip

#endif // CLIP_H_INCLUDED
