summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java133
2 files changed, 134 insertions, 2 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
index 8c80e9151..a0ec16578 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
@@ -4,7 +4,6 @@ import android.content.ContentResolver;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.ModelLoader;
@@ -77,7 +76,7 @@ class ApOkHttpUrlLoader implements ModelLoader<String, InputStream> {
@Nullable
@Override
public LoadData<InputStream> buildLoadData(@NonNull String model, int width, int height, @NonNull Options options) {
- return new LoadData<>(new ObjectKey(model), new OkHttpStreamFetcher(client, new GlideUrl(model)));
+ return new LoadData<>(new ObjectKey(model), new ResizingOkHttpStreamFetcher(client, new GlideUrl(model)));
}
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java
new file mode 100644
index 000000000..26f50e42f
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ResizingOkHttpStreamFetcher.java
@@ -0,0 +1,133 @@
+package de.danoeh.antennapod.core.glide;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Build;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import com.bumptech.glide.Priority;
+import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.google.android.exoplayer2.util.Log;
+import okhttp3.Call;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class ResizingOkHttpStreamFetcher extends OkHttpStreamFetcher {
+ private static final String TAG = "ResizingOkHttpStreamFetcher";
+ private static final int MAX_DIMENSIONS = 2000;
+ private static final int MAX_FILE_SIZE = 1024 * 1024; // 1 MB
+
+ private FileInputStream stream;
+ private File tempIn;
+ private File tempOut;
+
+ public ResizingOkHttpStreamFetcher(Call.Factory client, GlideUrl url) {
+ super(client, url);
+ }
+
+ @Override
+ public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
+ super.loadData(priority, new DataCallback<InputStream>() {
+ @Override
+ public void onDataReady(@Nullable InputStream data) {
+ if (data == null) {
+ callback.onDataReady(null);
+ return;
+ }
+ try {
+ tempIn = File.createTempFile("resize_", null);
+ tempOut = File.createTempFile("resize_", null);
+ OutputStream outputStream = new FileOutputStream(tempIn);
+ IOUtils.copy(data, outputStream);
+ outputStream.close();
+ IOUtils.closeQuietly(data);
+
+ if (tempIn.length() <= MAX_FILE_SIZE) {
+ try {
+ stream = new FileInputStream(tempIn);
+ callback.onDataReady(stream); // Just deliver the original, non-scaled image
+ } catch (FileNotFoundException fileNotFoundException) {
+ callback.onLoadFailed(fileNotFoundException);
+ }
+ return;
+ }
+
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ FileInputStream in = new FileInputStream(tempIn);
+ BitmapFactory.decodeStream(in, null, options);
+ IOUtils.closeQuietly(in);
+
+ if (Math.max(options.outHeight, options.outWidth) >= MAX_DIMENSIONS) {
+ double sampleSize = (double) Math.max(options.outHeight, options.outWidth) / MAX_DIMENSIONS;
+ options.inSampleSize = (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
+ }
+
+ options.inJustDecodeBounds = false;
+ in = new FileInputStream(tempIn);
+ Bitmap bitmap = BitmapFactory.decodeStream(in, null, options);
+ IOUtils.closeQuietly(in);
+
+ Bitmap.CompressFormat format = Build.VERSION.SDK_INT < 30
+ ? Bitmap.CompressFormat.WEBP : Bitmap.CompressFormat.WEBP_LOSSY;
+
+ int quality = 100;
+ while (true) {
+ FileOutputStream out = new FileOutputStream(tempOut);
+ bitmap.compress(format, quality, out);
+ IOUtils.closeQuietly(out);
+
+ if (tempOut.length() > 3 * MAX_FILE_SIZE && quality >= 45) {
+ quality -= 40;
+ } else if (tempOut.length() > 2 * MAX_FILE_SIZE && quality >= 25) {
+ quality -= 20;
+ } else if (tempOut.length() > MAX_FILE_SIZE && quality >= 15) {
+ quality -= 10;
+ } else if (tempOut.length() > MAX_FILE_SIZE && quality >= 10) {
+ quality -= 5;
+ } else {
+ break;
+ }
+ }
+
+ stream = new FileInputStream(tempOut);
+ callback.onDataReady(stream);
+ Log.d(TAG, "Compressed image from " + tempIn.length() / 1024
+ + " to " + tempOut.length() / 1024 + " kB (quality: " + quality + "%)");
+ } catch (IOException e) {
+ e.printStackTrace();
+
+ try {
+ stream = new FileInputStream(tempIn);
+ callback.onDataReady(stream); // Just deliver the original, non-scaled image
+ } catch (FileNotFoundException fileNotFoundException) {
+ e.printStackTrace();
+ callback.onLoadFailed(fileNotFoundException);
+ }
+ }
+ }
+
+ @Override
+ public void onLoadFailed(@NonNull Exception e) {
+ callback.onLoadFailed(e);
+ }
+ });
+ }
+
+ @Override
+ public void cleanup() {
+ IOUtils.closeQuietly(stream);
+ FileUtils.deleteQuietly(tempIn);
+ FileUtils.deleteQuietly(tempOut);
+ super.cleanup();
+ }
+}