/* Copyright 2017 Andrew Dawson * * This file is part of Tusky. * * Tusky is free software: you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with Tusky. If not, see * . */ package com.keylesspalace.tusky; import android.graphics.Bitmap; import android.os.AsyncTask; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.List; public class DownsizeImageTask extends AsyncTask { private Listener listener; private int sizeLimit; private List resultList; public DownsizeImageTask(int sizeLimit, Listener listener) { this.listener = listener; this.sizeLimit = sizeLimit; } public static Bitmap scaleDown(Bitmap source, float maxImageSize, boolean filter) { float ratio = Math.min(maxImageSize / source.getWidth(), maxImageSize / source.getHeight()); int width = Math.round(ratio * source.getWidth()); int height = Math.round(ratio * source.getHeight()); return Bitmap.createScaledBitmap(source, width, height, filter); } @Override protected Boolean doInBackground(Bitmap... bitmaps) { final int count = bitmaps.length; resultList = new ArrayList<>(count); for (int i = 0; i < count; i++) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); /* Unfortunately, there isn't a determined worst case compression ratio for image * formats. So, the only way to tell if they're too big is to compress them and * test, and keep trying at smaller sizes. The initial estimate should be good for * many cases, so it should only iterate once, but the loop is used to be absolutely * sure it gets downsized to below the limit. */ int iterations = 0; int scaledImageSize = 4096; do { stream.reset(); Bitmap bitmap = scaleDown(bitmaps[i], scaledImageSize, true); Bitmap.CompressFormat format; /* It's not likely the user will give transparent images over the upload limit, but * if they do, make sure the transparency is retained. */ if (!bitmap.hasAlpha()) { format = Bitmap.CompressFormat.JPEG; } else { format = Bitmap.CompressFormat.PNG; } bitmap.compress(format, 75, stream); scaledImageSize /= 2; iterations++; } while (stream.size() > sizeLimit); assert(iterations < 3); resultList.add(stream.toByteArray()); if (isCancelled()) { return false; } } return true; } @Override protected void onPostExecute(Boolean successful) { if (successful) { listener.onSuccess(resultList); } else { listener.onFailure(); } super.onPostExecute(successful); } public interface Listener { void onSuccess(List contentList); void onFailure(); } }