Skip to content

Commit

Permalink
use same algo for avatar placeholder
Browse files Browse the repository at this point in the history
  • Loading branch information
tobiasKaminsky authored and AndyScherzinger committed Oct 18, 2017
1 parent 620f9db commit c7ee4f1
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 16 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/owncloud/android/ui/TextDrawable.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@ public static TextDrawable createAvatar(String accountName, float radiusInDp) th
@NonNull
public static TextDrawable createNamedAvatar(String name, float radiusInDp) throws
UnsupportedEncodingException, NoSuchAlgorithmException {
int[] rgb = BitmapUtils.calculateRGB(name);
TextDrawable avatar = new TextDrawable(
name.substring(0, 1).toUpperCase(), rgb[0], rgb[1], rgb[2], radiusInDp);
return avatar;
int[] hsl = BitmapUtils.calculateHSL(name);
int[] rgb = BitmapUtils.HSLtoRGB(hsl[0], hsl[1], hsl[2], 1);

return new TextDrawable(name.substring(0, 1).toUpperCase(), rgb[0], rgb[1], rgb[2], radiusInDp);
}

/**
Expand Down
106 changes: 94 additions & 12 deletions src/main/java/com/owncloud/android/utils/BitmapUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@

import com.owncloud.android.lib.common.utils.Log_OC;

import org.apache.commons.codec.binary.Hex;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;

/**
* Utility class with methods for decoding Bitmaps.
*/
public class BitmapUtils {
public static final String TAG = BitmapUtils.class.getSimpleName();


/**
Expand Down Expand Up @@ -188,7 +189,7 @@ else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
*
* @param h Hue is specified as degrees in the range 0 - 360.
* @param s Saturation is specified as a percentage in the range 1 - 100.
* @param l Lumanance is specified as a percentage in the range 1 - 100.
* @param l Luminance is specified as a percentage in the range 1 - 100.
* @param alpha the alpha value between 0 - 1
* adapted from https://svn.codehaus.org/griffon/builders/gfxbuilder/tags/GFXBUILDER_0.2/
* gfxbuilder-core/src/main/com/camick/awt/HSLColor.java
Expand Down Expand Up @@ -267,17 +268,98 @@ private static float HueToRGB(float p, float q, float h) {
* @throws UnsupportedEncodingException if the charset is not supported
* @throws NoSuchAlgorithmException if the specified algorithm is not available
*/
public static int[] calculateRGB(String name) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// using adapted algorithm from /core/js/placeholder.js:50
byte[] seed = name.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
Integer seedMd5Int = String.format(Locale.ROOT, "%032x",
new BigInteger(1, md.digest(seed))).hashCode();
public static int[] calculateHSL(String name) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// using adapted algorithm from https://github.com/nextcloud/server/blob/master/core/js/placeholder.js#L126

String[] result = new String[]{"0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"};
double[] rgb = new double[]{0, 0, 0};
int sat = 70;
int lum = 68;
int modulo = 16;

String hash = name.toLowerCase().replaceAll("[^0-9a-f]", "");

if (!hash.matches("^[0-9a-f]{32}")) {
hash = md5(hash);
}

// Splitting evenly the string
for (int i = 0; i < hash.length(); i++) {
result[i % modulo] = result[i % modulo] + String.valueOf(Integer.parseInt(hash.substring(i, i + 1), 16));
}

double maxRange = Integer.MAX_VALUE;
float hue = (float) (seedMd5Int / maxRange * 360);
// Converting our data into a usable rgb format
// Start at 1 because 16%3=1 but 15%3=0 and makes the repartition even
for (int count = 1; count < modulo; count++) {
rgb[count % 3] += (Integer.parseInt(result[count]));
}

// Reduce values bigger than rgb requirements
rgb[0] = rgb[0] % 255;
rgb[1] = rgb[1] % 255;
rgb[2] = rgb[2] % 255;

double[] hsl = rgbToHsl(rgb[0], rgb[1], rgb[2]);

// Classic formula to check the brightness for our eye
// If too bright, lower the sat
double bright = Math.sqrt(0.299 * Math.pow(rgb[0], 2) + 0.587 * Math.pow(rgb[1], 2) + 0.114
* Math.pow(rgb[2], 2));

if (bright >= 200) {
sat = 60;
}

return new int[]{(int) (hsl[0] * 360), sat, lum};
}

private static double[] rgbToHsl(double r, double g, double b) {
r /= 255;
g /= 255;
b /= 255;

double max = Math.max(r, Math.max(g, b));
double min = Math.min(r, Math.min(g, b));
double h = (max + min) / 2;
double s;
double l = (max + min) / 2;

if (max == min) {
h = s = 0; // achromatic
} else {
double d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);

if (max == r) {
h = (g - b) / d + (g < b ? 6 : 0);
} else if (max == g) {
h = (b - r) / d + 2;
} else if (max == b) {
h = (r - g) / d + 4;
}
h /= 6;
}

double[] hsl = new double[]{0.0, 0.0, 0.0};
hsl[0] = h;
hsl[1] = s;
hsl[2] = l;

return hsl;
}

public static String md5(String string) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(string.getBytes());

return new String(Hex.encodeHex(md5.digest()));

} catch (Exception e) {
Log_OC.e(TAG, e.getMessage());
}

return BitmapUtils.HSLtoRGB(hue, 90.0f, 65.0f, 1.0f);
return "";
}

/**
Expand Down

0 comments on commit c7ee4f1

Please sign in to comment.