diff --git a/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java b/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java index 20ec77f03905..8e3805ea38e2 100644 --- a/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java @@ -15,6 +15,7 @@ import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.Canvas; +import android.graphics.ImageDecoder; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; @@ -24,6 +25,7 @@ import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.widget.ImageView; import com.owncloud.android.MainApp; @@ -33,9 +35,9 @@ import com.owncloud.android.lib.resources.users.StatusType; import com.owncloud.android.ui.StatusDrawable; -import org.apache.commons.codec.binary.Hex; -import java.nio.charset.Charset; +import java.io.File; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Locale; @@ -67,13 +69,20 @@ private BitmapUtils() { * @return decoded bitmap */ public static Bitmap decodeSampledBitmapFromFile(String srcPath, int reqWidth, int reqHeight) { - + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + // For API 28 and above, use ImageDecoder + try { + return ImageDecoder.decodeBitmap(ImageDecoder.createSource(new File(srcPath)), + (decoder, info, source) -> { + // Set the target size + decoder.setTargetSize(reqWidth, reqHeight); + }); + } catch (Exception exception) { + Log_OC.e("BitmapUtil", "Error decoding the bitmap from file: " + srcPath + ", exception: " + exception.getMessage()); + } + } // set desired options that will affect the size of the bitmap final Options options = new Options(); - options.inScaled = true; - options.inPurgeable = true; - options.inPreferQualityOverSpeed = false; - options.inMutable = false; // make a false load of the bitmap to get its dimensions options.inJustDecodeBounds = true; @@ -151,45 +160,53 @@ public static Bitmap rotateImage(Bitmap bitmap, String storagePath) { ExifInterface exifInterface = new ExifInterface(storagePath); int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); - Matrix matrix = new Matrix(); - - // 1: nothing to do - - // 2 - if (orientation == ExifInterface.ORIENTATION_FLIP_HORIZONTAL) { - matrix.postScale(-1.0f, 1.0f); - } - // 3 - else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { - matrix.postRotate(180); - } - // 4 - else if (orientation == ExifInterface.ORIENTATION_FLIP_VERTICAL) { - matrix.postScale(1.0f, -1.0f); - } - // 5 - else if (orientation == ExifInterface.ORIENTATION_TRANSPOSE) { - matrix.postRotate(-90); - matrix.postScale(1.0f, -1.0f); - } - // 6 - else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { - matrix.postRotate(90); - } - // 7 - else if (orientation == ExifInterface.ORIENTATION_TRANSVERSE) { - matrix.postRotate(90); - matrix.postScale(1.0f, -1.0f); - } - // 8 - else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { - matrix.postRotate(270); - } + if (orientation != ExifInterface.ORIENTATION_NORMAL) { + Matrix matrix = new Matrix(); + switch (orientation) { + // 2 + case ExifInterface.ORIENTATION_FLIP_HORIZONTAL: { + matrix.postScale(-1.0f, 1.0f); + break; + } + // 3 + case ExifInterface.ORIENTATION_ROTATE_180: { + matrix.postRotate(180); + break; + } + // 4 + case ExifInterface.ORIENTATION_FLIP_VERTICAL: { + matrix.postScale(1.0f, -1.0f); + break; + } + // 5 + case ExifInterface.ORIENTATION_TRANSPOSE: { + matrix.postRotate(-90); + matrix.postScale(1.0f, -1.0f); + break; + } + // 6 + case ExifInterface.ORIENTATION_ROTATE_90: { + matrix.postRotate(90); + break; + } + // 7 + case ExifInterface.ORIENTATION_TRANSVERSE: { + matrix.postRotate(90); + matrix.postScale(1.0f, -1.0f); + break; + } + // 8 + case ExifInterface.ORIENTATION_ROTATE_270: { + matrix.postRotate(270); + break; + } + } - // Rotate the bitmap - resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - if (!resultBitmap.equals(bitmap)) { - bitmap.recycle(); + // Rotate the bitmap + resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + if (!resultBitmap.equals(bitmap)) { + bitmap.recycle(); + } } } catch (Exception exception) { Log_OC.e("BitmapUtil", "Could not rotate the image: " + storagePath); @@ -207,8 +224,8 @@ public static int[] getImageResolution(String srcPath) { public static Color usernameToColor(String name) { String hash = name.toLowerCase(Locale.ROOT); - // already a md5 hash? - if (!hash.matches("([0-9a-f]{4}-?){8}$")) { + // Check if the input is already a valid MD5 hash (32 hex characters) + if (hash.length() != 32 || !hash.matches("[0-9a-f]+")) { try { hash = md5(hash); } catch (NoSuchAlgorithmException e) { @@ -229,22 +246,15 @@ public static Color usernameToColor(String name) { private static int hashToInt(String hash, int maximum) { int finalInt = 0; - int[] result = new int[hash.length()]; - // splitting evenly the string + // Sum the values of the hexadecimal digits for (int i = 0; i < hash.length(); i++) { - // chars in md5 goes up to f, hex: 16 - result[i] = Integer.parseInt(String.valueOf(hash.charAt(i)), 16) % 16; - } - - // adds up all results - for (int value : result) { - finalInt += value; + // Efficient hex char-to-int conversion + finalInt += Character.digit(hash.charAt(i), 16); } - // chars in md5 goes up to f, hex:16 - // make sure we're always using int in our operation - return Integer.parseInt(String.valueOf(Integer.parseInt(String.valueOf(finalInt), 10) % maximum), 10); + // Return the sum modulo maximum + return finalInt % maximum; } private static Color[] generateColors(int steps) { @@ -257,13 +267,9 @@ private static Color[] generateColors(int steps) { Color[] palette3 = mixPalette(steps, blue, red); Color[] resultPalette = new Color[palette1.length + palette2.length + palette3.length]; - System.arraycopy(palette1, 0, resultPalette, 0, palette1.length); - System.arraycopy(palette2, 0, resultPalette, palette1.length, palette2.length); - System.arraycopy(palette3, - 0, - resultPalette, - palette1.length + palette2.length, - palette1.length); + System.arraycopy(palette1, 0, resultPalette, 0, steps); + System.arraycopy(palette2, 0, resultPalette, steps, steps); + System.arraycopy(palette3, 0, resultPalette, steps * 2, steps); return resultPalette; } @@ -326,15 +332,21 @@ public boolean equals(@Nullable Object obj) { @Override public int hashCode() { - return r * 10000 + g * 1000 + b; + return (r << 16) + (g << 8) + b; } } public static String md5(String string) throws NoSuchAlgorithmException { MessageDigest md5 = MessageDigest.getInstance("MD5"); - md5.update(string.getBytes(Charset.defaultCharset())); + // Use UTF-8 for consistency + byte[] hashBytes = md5.digest(string.getBytes(StandardCharsets.UTF_8)); - return new String(Hex.encodeHex(md5.digest())); + StringBuilder hexString = new StringBuilder(32); + for (byte b : hashBytes) { + // Convert each byte to a 2-digit hex string + hexString.append(String.format("%02x", b)); + } + return hexString.toString(); } /**