Recode images to save cache space

This commit is contained in:
ByteHamster 2021-07-31 17:59:34 +02:00
parent c3b35f7d8d
commit 63c00a12a8
2 changed files with 134 additions and 2 deletions

View File

@ -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

View File

@ -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();
}
}