/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.getlantern.firetweet.util;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import com.nostra13.universalimageloader.utils.IoUtils;
import org.getlantern.firetweet.FiretweetConstants;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class BitmapUtils {
// Find the max x that 1 / x <= scale.
public static int computeSampleSize(final float scale) {
if (scale <= 0) return 1;
final int initialSize = Math.max(1, (int) Math.ceil(1 / scale));
return initialSize <= 8 ? MathUtils.nextPowerOf2(initialSize) : (initialSize + 7) / 8 * 8;
}
// This computes a sample size which makes the longer side at least
// minSideLength long. If that's not possible, return 1.
public static int computeSampleSizeLarger(final int w, final int h, final int minSideLength) {
final int initialSize = Math.max(w / minSideLength, h / minSideLength);
if (initialSize <= 1) return 1;
return initialSize <= 8 ? MathUtils.prevPowerOf2(initialSize) : initialSize / 8 * 8;
}
public static boolean downscaleImageIfNeeded(final File imageFile, final int quality) {
if (imageFile == null || !imageFile.isFile()) return false;
final String path = imageFile.getAbsolutePath();
final BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// Corrupted image, so return now.
if (o.outWidth <= 0 || o.outHeight <= 0) return false;
o.inJustDecodeBounds = false;
if (o.outWidth > FiretweetConstants.TWITTER_MAX_IMAGE_WIDTH || o.outHeight > FiretweetConstants.TWITTER_MAX_IMAGE_HEIGHT) {
// The image dimension is larger than Twitter's limit.
o.inSampleSize = Utils.calculateInSampleSize(o.outWidth, o.outHeight, FiretweetConstants.TWITTER_MAX_IMAGE_WIDTH,
FiretweetConstants.TWITTER_MAX_IMAGE_HEIGHT);
FileOutputStream fos = null;
try {
final Bitmap b = BitmapDecodeHelper.decode(path, o);
final Bitmap.CompressFormat format = Utils.getBitmapCompressFormatByMimetype(o.outMimeType,
Bitmap.CompressFormat.PNG);
fos = new FileOutputStream(imageFile);
return b.compress(format, quality, fos);
} catch (final OutOfMemoryError e) {
return false;
} catch (final FileNotFoundException e) {
// This shouldn't happen.
} catch (final IllegalArgumentException e) {
return false;
} finally {
IoUtils.closeSilently(fos);
}
} else if (imageFile.length() > FiretweetConstants.TWITTER_MAX_IMAGE_SIZE) {
// The file size is larger than Twitter's limit.
FileOutputStream fos = null;
try {
final Bitmap b = BitmapDecodeHelper.decode(path, o);
fos = new FileOutputStream(imageFile);
return b.compress(Bitmap.CompressFormat.JPEG, 80, fos);
} catch (final OutOfMemoryError e) {
return false;
} catch (final FileNotFoundException e) {
// This shouldn't happen.
} finally {
IoUtils.closeSilently(fos);
}
}
return true;
}
public static Bitmap getCircleBitmap(Bitmap bitmap) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final int color = Color.RED;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawOval(rectF, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
// Resize the bitmap if each side is >= targetSize * 2
public static Bitmap resizeDownIfTooBig(final Bitmap bitmap, final int targetSize, final boolean recycle) {
final int srcWidth = bitmap.getWidth();
final int srcHeight = bitmap.getHeight();
final float scale = Math.max((float) targetSize / srcWidth, (float) targetSize / srcHeight);
if (scale > 0.5f) return bitmap;
return resizeBitmapByScale(bitmap, scale, recycle);
}
private static Bitmap.Config getConfig(final Bitmap bitmap) {
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = Bitmap.Config.RGB_565;
}
return config;
}
private static Bitmap resizeBitmapByScale(final Bitmap bitmap, final float scale, final boolean recycle) {
final int width = Math.round(bitmap.getWidth() * scale);
final int height = Math.round(bitmap.getHeight() * scale);
if (width == bitmap.getWidth() && height == bitmap.getHeight()) return bitmap;
final Bitmap target = Bitmap.createBitmap(width, height, getConfig(bitmap));
final Canvas canvas = new Canvas(target);
canvas.scale(scale, scale);
final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (recycle) {
bitmap.recycle();
}
return target;
}
}