mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 17:27:45 +00:00
Resize image in attempts to get it to fit into the maxImageSize bytes.
Fixes #8803
This commit is contained in:
parent
cb78684282
commit
5b298b4a04
@ -10,14 +10,15 @@ import android.graphics.Rect;
|
|||||||
import android.graphics.YuvImage;
|
import android.graphics.YuvImage;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.WorkerThread;
|
import android.support.annotation.WorkerThread;
|
||||||
import android.support.media.ExifInterface;
|
import android.support.media.ExifInterface;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@ -42,9 +44,10 @@ public class BitmapUtil {
|
|||||||
private static final int MIN_COMPRESSION_QUALITY = 45;
|
private static final int MIN_COMPRESSION_QUALITY = 45;
|
||||||
private static final int MAX_COMPRESSION_ATTEMPTS = 5;
|
private static final int MAX_COMPRESSION_ATTEMPTS = 5;
|
||||||
private static final int MIN_COMPRESSION_QUALITY_DECREASE = 5;
|
private static final int MIN_COMPRESSION_QUALITY_DECREASE = 5;
|
||||||
|
private static final int MAX_IMAGE_HALF_SCALES = 3;
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static <T> ScaleResult createScaledBytes(Context context, T model, MediaConstraints constraints)
|
public static <T> ScaleResult createScaledBytes(@NonNull Context context, @NonNull T model, @NonNull MediaConstraints constraints)
|
||||||
throws BitmapDecodingException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
return createScaledBytes(context, model,
|
return createScaledBytes(context, model,
|
||||||
@ -54,7 +57,24 @@ public class BitmapUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static <T> ScaleResult createScaledBytes(Context context, T model, int maxImageWidth, int maxImageHeight, int maxImageSize)
|
public static <T> ScaleResult createScaledBytes(@NonNull Context context,
|
||||||
|
@NonNull T model,
|
||||||
|
final int maxImageWidth,
|
||||||
|
final int maxImageHeight,
|
||||||
|
final int maxImageSize)
|
||||||
|
throws BitmapDecodingException
|
||||||
|
{
|
||||||
|
return createScaledBytes(context, model, maxImageWidth, maxImageHeight, maxImageSize, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private static <T> ScaleResult createScaledBytes(@NonNull Context context,
|
||||||
|
@NonNull T model,
|
||||||
|
final int maxImageWidth,
|
||||||
|
final int maxImageHeight,
|
||||||
|
final int maxImageSize,
|
||||||
|
final int sizeAttempt,
|
||||||
|
int totalAttempts)
|
||||||
throws BitmapDecodingException
|
throws BitmapDecodingException
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@ -75,15 +95,17 @@ public class BitmapUtil {
|
|||||||
throw new BitmapDecodingException("Unable to decode image");
|
throw new BitmapDecodingException("Unable to decode image");
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "Initial scaled bitmap has size of " + scaledBitmap.getByteCount() + " bytes.");
|
Log.i(TAG, String.format(Locale.US,"Initial scaled bitmap has size of %d bytes.", scaledBitmap.getByteCount()));
|
||||||
|
Log.i(TAG, String.format(Locale.US, "Max dimensions %d x %d, %d bytes", maxImageWidth, maxImageHeight, maxImageSize));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
do {
|
do {
|
||||||
|
totalAttempts++;
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
scaledBitmap.compress(CompressFormat.JPEG, quality, baos);
|
scaledBitmap.compress(CompressFormat.JPEG, quality, baos);
|
||||||
bytes = baos.toByteArray();
|
bytes = baos.toByteArray();
|
||||||
|
|
||||||
Log.d(TAG, "iteration with quality " + quality + " size " + (bytes.length / 1024) + "kb");
|
Log.d(TAG, "iteration with quality " + quality + " size " + bytes.length + " bytes.");
|
||||||
if (quality == MIN_COMPRESSION_QUALITY) break;
|
if (quality == MIN_COMPRESSION_QUALITY) break;
|
||||||
|
|
||||||
int nextQuality = (int)Math.floor(quality * Math.sqrt((double)maxImageSize / bytes.length));
|
int nextQuality = (int)Math.floor(quality * Math.sqrt((double)maxImageSize / bytes.length));
|
||||||
@ -95,14 +117,22 @@ public class BitmapUtil {
|
|||||||
while (bytes.length > maxImageSize && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
while (bytes.length > maxImageSize && attempts++ < MAX_COMPRESSION_ATTEMPTS);
|
||||||
|
|
||||||
if (bytes.length > maxImageSize) {
|
if (bytes.length > maxImageSize) {
|
||||||
throw new BitmapDecodingException("Unable to scale image below: " + bytes.length);
|
if (sizeAttempt <= MAX_IMAGE_HALF_SCALES) {
|
||||||
|
scaledBitmap.recycle();
|
||||||
|
scaledBitmap = null;
|
||||||
|
|
||||||
|
Log.i(TAG, "Halving dimensions and retrying.");
|
||||||
|
return createScaledBytes(context, model, maxImageWidth / 2, maxImageHeight / 2, maxImageSize, sizeAttempt + 1, totalAttempts);
|
||||||
|
} else {
|
||||||
|
throw new BitmapDecodingException("Unable to scale image below " + bytes.length + " bytes.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes.length <= 0) {
|
if (bytes.length <= 0) {
|
||||||
throw new BitmapDecodingException("Decoding failed. Bitmap has a length of " + bytes.length + " bytes.");
|
throw new BitmapDecodingException("Decoding failed. Bitmap has a length of " + bytes.length + " bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "createScaledBytes(" + model.toString() + ") -> quality " + Math.min(quality, MAX_COMPRESSION_QUALITY) + ", " + attempts + " attempt(s)");
|
Log.i(TAG, String.format(Locale.US, "createScaledBytes(%s) -> quality %d, %d attempt(s) over %d sizes.", model.getClass().getName(), quality, totalAttempts, sizeAttempt));
|
||||||
|
|
||||||
return new ScaleResult(bytes, scaledBitmap.getWidth(), scaledBitmap.getHeight());
|
return new ScaleResult(bytes, scaledBitmap.getWidth(), scaledBitmap.getHeight());
|
||||||
} finally {
|
} finally {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user