/*
* Created by Itzik Braun on 12/3/2015.
* Copyright (c) 2015 deluge. All rights reserved.
*
* Last Modification at: 3/12/15 4:27 PM
*/
package com.braunster.chatsdk.Utils;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.media.ExifInterface;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
import com.braunster.chatsdk.network.BDefines;
import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class ImageUtils {
public static final String TAG = ImageUtils.class.getSimpleName();
public static final boolean DEBUG = Debug.ImageUtils;
/**
* Constructing a bitmap that contains the given bitmaps(max is three).
*
* For given two bitmaps the result will be a half and half bitmap.
*
* For given three the result will be a half of the first bitmap and the second
* half will be shared equally by the two others.
*
* @param bitmaps Array of bitmaps to use for the final image.
* @param width width of the final image, A positive number.
* @param height height of the final image, A positive number.
*
* @return A Bitmap containing the given images.
* */
@Nullable public static Bitmap getMixImagesBitmap(@Size(min = 1) int width,@Size(min = 1) int height, @NonNull Bitmap...bitmaps){
if (height == 0 || width == 0) return null;
if (bitmaps.length == 0) return null;
Bitmap finalImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(finalImage);
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);
if (bitmaps.length == 2){
canvas.drawBitmap(ThumbnailUtils.extractThumbnail(bitmaps[0], width/2, height), 0, 0, paint);
canvas.drawBitmap(ThumbnailUtils.extractThumbnail(bitmaps[1], width/2, height), width/2, 0, paint);
}
else{
canvas.drawBitmap(ThumbnailUtils.extractThumbnail(bitmaps[0], width/2, height), 0, 0, paint);
canvas.drawBitmap(ThumbnailUtils.extractThumbnail(bitmaps[1], width/2, height/2), width/2, 0, paint);
canvas.drawBitmap(ThumbnailUtils.extractThumbnail(bitmaps[2], width/2, height/2), width/2, height/2, paint);
}
return finalImage;
}
/** Constructing a bitmap with the given text written in it.*/
public static Bitmap getInitialsBitmap(int backGroundColor, int textColor, String initials){
int size = BDefines.ImageProperties.INITIALS_IMAGE_SIZE;
float textSize = BDefines.ImageProperties.INITIALS_TEXT_SIZE;
int textSpace = size/2;
// Create bitmap and canvas to draw to
Bitmap b = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
Canvas c= new Canvas(b);
// Draw background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG
| Paint.LINEAR_TEXT_FLAG);
paint.setStyle(Paint.Style.FILL);
paint.setColor(backGroundColor);
c.drawPaint(paint);
// Draw text
c.save();
Bitmap textBitmap = textAsBitmap(initials, textSize, textColor);
c.drawBitmap(textAsBitmap(initials, textSize, textColor), textSpace - textBitmap.getWidth()/2, textSpace - textBitmap.getHeight()/2, null);
c.restore();
return b;
}
/** @return a bitmap with text.*/
private static Bitmap textAsBitmap(String text, float textSize, int textColor) {
Paint paint = new Paint();
paint.setTextSize(textSize);
paint.setColor(textColor);
paint.setTextAlign(Paint.Align.LEFT);
int width = (int) (paint.measureText(text) + 0.5f); // round
float baseline = (int) (-paint.ascent() + 0.5f); // ascent() is negative
int height = (int) (baseline + paint.descent() + 0.5f);
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawText(text, 0, baseline, paint);
return image;
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap loadBitmapFromFile(String photoPath){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Matrix matrix = null;
try {
ExifInterface exif = new ExifInterface(photoPath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
matrix = null;
break;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
default:
matrix = null;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeFile(photoPath, options);
if (matrix != null)
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return bitmap;
}
public static Bitmap scaleImage(Bitmap bitmap, int boxSize){
if (boxSize == 0)
return null;
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) boxSize) / bitmap.getWidth();
float yScale = ((float) boxSize) / bitmap.getHeight();
float scale = (xScale <= yScale) ? xScale : yScale;
// Create a matrix for the scaling and add the scaling data
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
// Create a new bitmap and convert it to a format understood by the ImageView
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
public static int[] calcNewImageSize(int[] imgDimensions, int bounds){
int[] dimestions = new int[2];
// Get current dimensions
int width = imgDimensions[0];
int height = imgDimensions[1];
// Determine how much to scale: the dimension requiring less scaling is
// closer to the its side. This way the image always stays inside your
// bounding box AND either x/y axis touches it.
float xScale = ((float) bounds) / width;
float yScale = ((float) bounds) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
dimestions[0] = (int) (width * scale);
dimestions[1] = (int) (height * scale);
return dimestions;
}
public static Bitmap getCompressed(String filePath){
return getCompressed(filePath, BDefines.ImageProperties.MAX_WIDTH_IN_PX, BDefines.ImageProperties.MAX_HEIGHT_IN_PX);
}
/*http://voidcanvas.com/whatsapp-like-image-compression-in-android/*/
public static Bitmap getCompressed(String filePath, float maxWidth, float maxHeight){
Bitmap scaledBitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
// by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
// you try the use the bitmap here, you will get null.
options.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
int actualHeight = options.outHeight;
int actualWidth = options.outWidth;
// max Height and width values of the compressed image is taken as 816x612
float imgRatio = (float) actualWidth / (float) actualHeight;
float maxRatio = maxWidth / maxHeight;
// width and height values are set maintaining the aspect ratio of the image
if (actualHeight > maxHeight || actualWidth > maxWidth)
{
if (imgRatio < maxRatio) {
imgRatio = maxHeight / actualHeight;
actualWidth = (int) (imgRatio * actualWidth);
actualHeight = (int) maxHeight;
}
else if (imgRatio > maxRatio)
{
imgRatio = maxWidth / actualWidth;
actualHeight = (int) (imgRatio * actualHeight);
actualWidth = (int) maxWidth;
} else
{
actualHeight = (int) maxHeight;
actualWidth = (int) maxWidth;
}
}
// setting inSampleSize value allows to load a scaled down version of the original image
options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
// inJustDecodeBounds set to false to load the actual bitmap
options.inJustDecodeBounds = false;
// this options allow android to claim the bitmap memory if it runs low on memory
options.inPurgeable = true;
options.inInputShareable = true;
options.inTempStorage = new byte[16 * 1024];
try {
// load the bitmap from its path
bmp = BitmapFactory.decodeFile(filePath, options);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
}
if (actualHeight <= 0 || actualWidth <= 0)
return null;
try {
scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight,Bitmap.Config.ARGB_8888);
} catch (OutOfMemoryError exception) {
exception.printStackTrace();
return null;
}
float ratioX = actualWidth / (float) options.outWidth;
float ratioY = actualHeight / (float) options.outHeight;
float middleX = actualWidth / 2.0f;
float middleY = actualHeight / 2.0f;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));
// check the rotation of the image and display it properly
ExifInterface exif;
try {
exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
true);
} catch (IOException e) {
e.printStackTrace();
}
return scaledBitmap;
}
public static void saveBitmapToFile(File file, Bitmap bitmap){
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
if (out != null)
out.close();
} catch(Throwable ignore) {}
}
}
public static String getDimensionAsString(Bitmap bitmap){
if (bitmap == null)
throw new NullPointerException("Bitmap cannot be null");
return WIDTH + bitmap.getWidth() + DIVIDER + HEIGHT + bitmap.getHeight();
}
public static int[] getDimensionsFromString(String dimensions){
if (StringUtils.isEmpty(dimensions))
throw new IllegalArgumentException("dimensions cannot be empty");
String[] dimen = dimensions.split(DIVIDER);
if (dimen.length != 2)
throw new IllegalArgumentException("The dimensions string us invalid.");
// Removing the letters from the String.
dimen[0] = dimen[0].substring(1);
dimen[1] = dimen[1].substring(1);
return new int[]{ Integer.parseInt(dimen[0]), Integer.parseInt(dimen[1]) };
}
public static final String DIVIDER = "&", HEIGHT = "H", WIDTH = "W";
public static void scanFilePathForGallery(Context context, String path) {
if (context == null)
return;
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(path);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
context.sendBroadcast(mediaScanIntent);
}
public static byte[] getImageByteArray(Bitmap bitmap){
return getImageByteArray(bitmap, 50);
}
public static byte[] getImageByteArray(Bitmap bitmap, int quality){
// Converting file to a JPEG and then to byte array.
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
return stream.toByteArray();
}
}