weshatheleopard/rubyXL

View on GitHub
lib/rubyXL/convenience_methods/color.rb

Summary

Maintainability
A
1 hr
Test Coverage
module RubyXL
  module ColorConvenienceMethods
    def get_rgb(workbook)
      if rgb then
        return rgb
      elsif theme then
        theme_color = workbook.theme.get_theme_color(theme)
        rgb_color = theme_color && theme_color.a_srgb_clr
        color_value = rgb_color && rgb_color.val
        return nil if color_value.nil?

        RubyXL::RgbColor.parse(color_value).to_hls.apply_tint(tint).to_rgb.to_s
      end
    end
  end

  module ColorConvenienceClasses
    # https://ciintelligence.blogspot.com/2012/02/converting-excel-theme-color-and-tint.html
    class RgbColor
      attr_accessor :r, :g, :b, :a

      def to_hls
        hls_color = HlsColor.new

        # Note that we are overriding accessors with local vars here:
        r = self.r / 255.0
        g = self.g / 255.0
        b = self.b / 255.0

        hls_color.a = (self.a || 0) / 255.0

        min = [r, g, b].min
        max = [r, g, b].max
        delta = max - min

        if (max == min) then
          hls_color.h = hls_color.s = 0
          hls_color.l = max
          return hls_color
        end

        hls_color.l = (min + max) / 2

        if (hls_color.l < 0.5) then
          hls_color.s = delta / (max + min);
        else
          hls_color.s = delta / (2.0 - max - min);
        end

        hls_color.h = (g - b) / delta       if (r == max)
        hls_color.h = 2.0 + (b - r) / delta if (g == max)
        hls_color.h = 4.0 + (r - g) / delta if (b == max)

        hls_color.h *= 60;
        hls_color.h += 360 if hls_color.h < 0

        hls_color
      end

      def self.parse(str)
        r, g, b, a = str.unpack('A2A2A2A2')

        rgb_color = RgbColor.new
        rgb_color.r = r && r.to_i(16)
        rgb_color.g = g && g.to_i(16)
        rgb_color.b = b && b.to_i(16)
        rgb_color.a = a && a.to_i(16)

        rgb_color
      end

      def to_s
        if a && a != 0 then
          format('%02x%02x%02x%02x', r, g, b, a)
        else
          format('%02x%02x%02x', r, g, b)
        end
      end
    end

    class HlsColor
      attr_accessor :h, :l, :s, :a

      def to_rgb
        rgb_color = RgbColor.new

        r = g = b = l

        if s != 0 then
          t1 = nil

          if l < 0.5 then
            t1 = l * (1.0 + s)
          else
            t1 = l + s - (l * s)
          end

          t2 = 2.0 * l - t1;
          h = self.h / 360.0

          t_r = h + (1.0 / 3.0)
          r = set_color(t1, t2, t_r)

          t_g = h;
          g = set_color(t1, t2, t_g)

          t_b = h - (1.0 / 3.0);
          b = set_color(t1, t2, t_b)
        end

        rgb_color.r = (r * 255).round(0).to_i
        rgb_color.g = (g * 255).round(0).to_i
        rgb_color.b = (b * 255).round(0).to_i

        rgb_color.a = (a * 255).round(0).to_i

        rgb_color
      end

      def set_color(t1, t2, t3)
        color = 0

        t3 += 1.0 if (t3 < 0)
        t3 -= 1.0 if (t3 > 1)

        if (6.0 * t3 < 1) then
          color = t2 + (t1 - t2) * 6.0 * t3;
        elsif (2.0 * t3 < 1) then
          color = t1;
        elsif (3.0 * t3 < 2) then
          color = t2 + (t1 - t2) * ((2.0 / 3.0) - t3) * 6.0;
        else
          color = t2;
        end

        color
      end
      private :set_color

      def apply_tint(tint)
        return self if tint.nil? || tint == 0

        if tint < 0 then
          self.l = l * (1.0 + tint);
        else
          self.l = l * (1.0 - tint) + tint;
        end

        self
      end
    end
  end

  RubyXL::Color.send(:include, RubyXL::ColorConvenienceMethods) # ruby 2.1 compat
  include(RubyXL::ColorConvenienceClasses)
end