Dart字符串到十六进制代码颜色

304 阅读1分钟

这是一个从TypeScript翻译过来的算法。

该算法适用于Avatar显示的场景下,假如头像图片不存在的情况下,根据用户名来算出一个显示的背景色。

其运行的效果如下:

屏幕截图 2024-09-06 153739.png

import 'package:flutter/material.dart';

/// 字符串到十六进制代码颜色
/// 翻译自TypeScript库:https://github.com/HugoJBello/string-to-hex-code-color
/// 在线转换工具:https://string-to-hex-code-color.firebaseapp.com/
class String2HexCodeColor {
  double defaultShadePercentage = 0;

  String2HexCodeColor({double? defaultShadePercentage}) {
    if (defaultShadePercentage != null) {
      this.defaultShadePercentage = defaultShadePercentage;
    }
  }

  _shadeColor(String color, double? percent) {
    percent ??= defaultShadePercentage;

    final f = int.parse(color.substring(1), radix: 16);
    final t = percent < 0 ? 0 : 255;
    final p = percent < 0 ? percent * -1 : percent;

    final R = f >> 16;
    final G = f >> 8 & 0x00FF;
    final B = f & 0x0000FF;

    final n1 = ((t - R) * p).round();
    final n2 = ((t - G) * p).round();
    final n3 = ((t - B) * p).round();

    final total = 0x1000000 + (n1 + R) * 0x10000 + (n2 + G) * 0x100 + (n3 + B);

    final result = '#${total.toRadixString(16).substring(1)}';
    return result;
  }

  int _hash(String text) {
    int hash = 0;
    for (int i = 0; i < text.length; i++) {
      final char = text.codeUnitAt(i);
      hash = char + ((hash << 5) - hash);
    }
    return hash;
  }

  _preHash(String text) {
    int hash = 0;
    if (text.isEmpty) {
      return hash;
    }

    for (int i = 0; i < text.length; i++) {
      final char = text.codeUnitAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // Convert to 32bit integer
    }

    return hash;
  }

  static Color fromHex(String hexString) {
    final buffer = StringBuffer();
    if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
    buffer.write(hexString.replaceFirst('#', ''));
    return Color(int.parse(buffer.toString(), radix: 16));
  }

  Color stringToColor(String text, {double? shadePercentage}) {
    if (text.length < 4) {
      text = text + _preHash(text).toString();
    }

    var hash = _hash(text);

    String colour = '#';
    for (int i = 0; i < 3; i++) {
      final value = (hash >> (i * 8)) & 0xFF;
      String str = value.toRadixString(16).padLeft(2, '0');
      str = '00$str';
      colour += str.substring(str.length - 2);
    }

    if (shadePercentage != null || (defaultShadePercentage != 0)) {
      colour = _shadeColor(colour, shadePercentage);
    }

    // debugPrint('[$text] 颜色值: $colour');

    return fromHex(colour);
  }
}

测试代码:

void main() {
  group("String2HexCodeColor", () {
    test('color test', () async {
      final string2HexCodeColor = String2HexCodeColor();

      Color cName = string2HexCodeColor.stringToColor("name");
      debugPrint('name: $cName');
      expect(cName, const Color(0xff8b7a33));

      final cA = string2HexCodeColor.stringToColor("a");
      expect(cA, const Color(0xff3f7301));
      debugPrint('a: $cA');

      final cB = string2HexCodeColor.stringToColor("b");
      expect(cB, const Color(0xff017701));
      debugPrint('b: $cB');

      final cC = string2HexCodeColor.stringToColor("c");
      expect(cC, const Color(0xffc37a01));
      debugPrint('c: $cC');
    });

    test('shade test', () async {
      final string2HexCodeColor = String2HexCodeColor();

      expect(string2HexCodeColor.stringToColor("a", shadePercentage: 0.5), const Color(0xff9fb980));
      expect(string2HexCodeColor.stringToColor("a", shadePercentage: 0.2), const Color(0xff658f34));
      expect(string2HexCodeColor.stringToColor("a"), const Color(0xff3f7301));
      expect(string2HexCodeColor.stringToColor("a", shadePercentage: -0.2), const Color(0xff325c01));
      expect(string2HexCodeColor.stringToColor("a", shadePercentage: -0.5), const Color(0xff1f3900));
    });
  });
}