Skip to content

Instantly share code, notes, and snippets.

@dhagz
Created September 18, 2018 08:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhagz/c6dbfa2f42afc3c008fd17996cdcb91a to your computer and use it in GitHub Desktop.
Save dhagz/c6dbfa2f42afc3c008fd17996cdcb91a to your computer and use it in GitHub Desktop.
JPEG Compressor
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.support.annotation.NonNull;
import android.support.media.ExifInterface;
import android.util.DisplayMetrics;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
/**
* @author Dhagz
* @since 5/11/2016
*/
public class JpegCompressor {
private static final String TAG = JpegCompressor.class.getSimpleName();
private static final String SUFFIX_COMPRESSED = "_compressed";
private File[] imageFiles;
private int quality;
private int width;
private int height;
private Integer smallestDimen;
private String fileNameSuffix;
public JpegCompressor(File originalImage) {
if (originalImage.isDirectory()) {
imageFiles = originalImage.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
return isEndsWithJpeg(filename);
}
});
} else if (originalImage.isFile() && isEndsWithJpeg(originalImage.getName())) {
imageFiles = new File[] {
originalImage
};
}
this.width = -1;
this.height = -1;
this.quality = 100;
this.fileNameSuffix = SUFFIX_COMPRESSED;
this.smallestDimen = null;
}
private boolean isEndsWithJpeg(String filename) {
filename = filename.trim().toLowerCase();
return filename.endsWith(".jpeg") || filename.endsWith(".jpg");
}
private Bitmap createBitmap(File originalImage) {
Bitmap origBitmap = BitmapFactory.decodeFile(originalImage.getAbsolutePath());
int origWidth = origBitmap.getWidth();
int origHeight = origBitmap.getHeight();
if (this.width == -1 && this.height == -1 && this.smallestDimen == null) {
// DO NOT CHANGE WITH OF HEIGHT
return origBitmap;
} else {
if (this.smallestDimen != null) {
// FIND THE SMALLEST DIMENSION AND SET IT
if (origHeight > origWidth) {
// portrait
this.width = this.smallestDimen;
this.height = (int) (((float) this.smallestDimen / origWidth) * origHeight);
} else {
// landscape
this.height = this.smallestDimen;
this.width = (int) (((float) this.smallestDimen / origHeight) * origWidth);
}
} else {
// ASPECT WIDTH OR ASPECT HEIGHT
if (this.width == -1) {
// set the width based on the provided height
this.width = (int) (((float) this.height / origHeight) * origWidth);
} else if (this.height == -1) {
// set the height based on the provided width
this.height = (int) (((float) this.width / origWidth) * origHeight);
}
}
// SET THE COMPRESSED BITMAP
Bitmap compressedBitmap =
Bitmap.createScaledBitmap(origBitmap, this.width, this.height, false);
// IDENTIFY THE ORIENTATION
Bitmap resultBitmap = null;
try {
ExifInterface exifInterface = new ExifInterface(originalImage.getAbsolutePath());
int orientation;
try {
orientation = Integer.parseInt(exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION));
} catch (Exception e) {
orientation = 1;
}
Matrix matrix = new Matrix();
boolean isFlipped = false;
int rotation = 0;
switch (orientation) {
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.preScale(-1.0f, 1.0f);
isFlipped = true;
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.preScale(1.0f, -1.0f);
isFlipped = true;
break;
case ExifInterface.ORIENTATION_NORMAL:
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotation = 270;
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
break;
case ExifInterface.ORIENTATION_UNDEFINED:
break;
}
if (rotation > 0) {
Log.i(TAG, "exif_orientation: " + rotation);
matrix.postRotate(rotation);
Bitmap scaledBitmap =
Bitmap.createScaledBitmap(compressedBitmap, compressedBitmap.getWidth(),
compressedBitmap.getHeight(), true);
resultBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(),
scaledBitmap.getHeight(), matrix, true);
}
if (isFlipped) {
Matrix m = new Matrix();
m.preScale(-1, 1);
resultBitmap = Bitmap.createBitmap(compressedBitmap, 0, 0, compressedBitmap.getWidth(),
compressedBitmap.getHeight(), m, false);
resultBitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT);
}
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
resultBitmap = null;
// eh di wow!
}
if (resultBitmap == null) {
return compressedBitmap;
} else {
return resultBitmap;
}
}
}
private String generateFileNameSuffix(String fileName, String suffix) {
int lastDotInd = fileName.lastIndexOf('.');
return fileName.substring(0, lastDotInd) + suffix + fileName.substring(lastDotInd);
}
public JpegCompressor setQuality(int quality) {
this.quality = quality;
return this;
}
public JpegCompressor setWidth(int width) {
this.width = width;
return this;
}
public JpegCompressor setHeight(int height) {
this.height = height;
return this;
}
public JpegCompressor setFileNameSuffix(String fileNameSuffix) {
if (isEndsWithJpeg(fileNameSuffix)) this.fileNameSuffix = fileNameSuffix;
return this;
}
public JpegCompressor setSmallestDimension(int smallestDimen) {
this.smallestDimen = smallestDimen;
return this;
}
public JpegCompressor aspectWidth(int width) {
this.width = width;
this.height = -1;
return this;
}
public JpegCompressor aspectHeight(int height) {
this.width = -1;
this.height = height;
return this;
}
/**
* Saves the compressed image to the same directory as of the original but the file name will
* have a '_compressed' suffix.
*/
public void toJpeg() {
toJpeg(null, null);
}
/**
* Save the compressed image to the directory where the original image is located,
* with a {@code fileName} file name.
*
* @param fileName the file name of the compressed image.
*/
public void toJpeg(String fileName) {
toJpeg(null, fileName);
}
/**
* Saves the compressed image to the {@code dir} provided.
* <p/>
* If {@code dir} is a file, compressed image will be the dir provided.
* <p/>
* If {@code dir} is a directory, the file name to be used is the file name of the original
* image with a '_compressed' suffix.
*
* @param dir file or directory to where the compressed image will be placed.
*/
public void toJpeg(@NonNull File dir) {
if (!dir.exists()) {
if (dir.mkdirs()) {
toJpeg(dir, null);
}
} else {
if (dir.isDirectory()) {
toJpeg(dir, null);
} else {
toJpeg(dir.getParentFile(), dir.getName());
}
}
}
/**
* Saves the compressed image to the {@code dir} provided, with the {@code fileName} file name.
* <p/>
* If {@code dir} is a file, compressed image will be the dir provided,
* thus the {@code fileName} parameter value will be discarded.
*
* @param dir the directory to where the compressed image will be placed.
* @param fileName the file name of the compressed image.
*/
public void toJpeg(File dir, String fileName) {
// if dir is a file and file name is null or empty, get the parent directory of dir file
// and set the dir file name as the file name.
if (dir != null && dir.isFile()) {
fileName = dir.getName();
dir = dir.getParentFile();
}
int len = this.imageFiles.length;
for (int i = 0; i < len; i++) {
try {
Bitmap scaledBitmap = createBitmap(imageFiles[i]);
Log.i(TAG, "file: " + imageFiles[i].getAbsolutePath());
Log.i(TAG, "width: " + scaledBitmap.getWidth());
Log.i(TAG, "height: " + scaledBitmap.getHeight());
Log.i(TAG, "quality: " + this.quality);
// set file name if not provided
if (fileName == null) {
fileName = generateFileNameSuffix(imageFiles[i].getName(), this.fileNameSuffix);
}
// add jpeg extension if the file name does not have it
if (!(fileName.trim().toLowerCase().endsWith(".jpeg") || fileName.trim()
.toLowerCase()
.endsWith(".jpg"))) {
fileName += ".jpg";
}
if (dir == null) {
dir = imageFiles[i].getParentFile();
}
String fn = len > 1 ? generateFileNameSuffix(fileName, " (" + (i + 1) + ")") : fileName;
FileOutputStream os = new FileOutputStream(new File(dir, fn));
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, this.quality, os);
try {
os.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage(), e);
}
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment