Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed bug #294 #278 #295

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 92 additions & 168 deletions library/src/main/java/top/zibin/luban/Checker.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package top.zibin.luban;

import android.graphics.BitmapFactory;
import android.util.Log;
import android.media.ExifInterface;

import java.io.ByteArrayOutputStream;
import java.io.File;
Expand All @@ -10,191 +10,115 @@
import java.util.Arrays;

enum Checker {
SINGLE;
SINGLE;

private static final String TAG = "Luban";
private static final String TAG = "Luban";

private static final String JPG = ".jpg";
private static final String JPG = ".jpg";

private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};

/**
* Determine if it is JPG.
*
* @param is image file input stream
*/
boolean isJPG(InputStream is) {
return isJPG(toByteArray(is));
}

/**
* Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
*/
int getOrientation(InputStream is) {
return getOrientation(toByteArray(is));
}

private boolean isJPG(byte[] data) {
if (data == null || data.length < 3) {
return false;
/**
* Determine if it is JPG.
*
* @param is image file input stream
*/
boolean isJPG(InputStream is) {
return isJPG(toByteArray(is));
}
byte[] signatureB = new byte[]{data[0], data[1], data[2]};
return Arrays.equals(JPEG_SIGNATURE, signatureB);
}

private int getOrientation(byte[] jpeg) {
if (jpeg == null) {
return 0;
/**
* Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
*/
int getOrientation(String filePath) {
ExifInterface localExifInterface;
int angle = 0;
try {
localExifInterface = new ExifInterface(filePath);
int orientation = localExifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
angle = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
angle = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
angle = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return angle;
}

int offset = 0;
int length = 0;

// ISO/IEC 10918-1:1993(E)
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
int marker = jpeg[offset] & 0xFF;

// Check if the marker is a padding.
if (marker == 0xFF) {
continue;
}
offset++;

// Check if the marker is SOI or TEM.
if (marker == 0xD8 || marker == 0x01) {
continue;
}
// Check if the marker is EOI or SOS.
if (marker == 0xD9 || marker == 0xDA) {
break;
}

// Get the length and check if it is reasonable.
length = pack(jpeg, offset, 2, false);
if (length < 2 || offset + length > jpeg.length) {
Log.e(TAG, "Invalid length");
return 0;
}

// Break if the marker is EXIF in APP1.
if (marker == 0xE1 && length >= 8
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
&& pack(jpeg, offset + 6, 2, false) == 0) {
offset += 8;
length -= 8;
break;
}

// Skip other markers.
offset += length;
length = 0;
private boolean isJPG(byte[] data) {
if (data == null || data.length < 3) {
return false;
}
byte[] signatureB = new byte[]{data[0], data[1], data[2]};
return Arrays.equals(JPEG_SIGNATURE, signatureB);
}

// JEITA CP-3451 Exif Version 2.2
if (length > 8) {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
Log.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);

// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
Log.e(TAG, "Invalid offset");
return 0;
}
offset += count;
length -= count;

// Get the count and go through all the elements.
count = pack(jpeg, offset - 2, 2, littleEndian);
while (count-- > 0 && length >= 12) {
// Get the tag and check if it is orientation.
tag = pack(jpeg, offset, 2, littleEndian);
if (tag == 0x0112) {
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
switch (orientation) {
case 1:
return 0;
case 3:
return 180;
case 6:
return 90;
case 8:
return 270;
}
Log.e(TAG, "Unsupported orientation");
return 0;
String extSuffix(InputStreamProvider input) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input.open(), null, options);
return options.outMimeType.replace("image/", ".");
} catch (Exception e) {
return JPG;
}
offset += 12;
length -= 12;
}
}

Log.e(TAG, "Orientation not found");
return 0;
}

String extSuffix(InputStreamProvider input) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input.open(), null, options);
return options.outMimeType.replace("image/", ".");
} catch (Exception e) {
return JPG;
boolean needCompress(int leastCompressSize, String path) {
if (leastCompressSize > 0) {
File source = new File(path);
return source.exists() && source.length() > (leastCompressSize << 10);
}
return true;
}
}

boolean needCompress(int leastCompressSize, String path) {
if (leastCompressSize > 0) {
File source = new File(path);
return source.exists() && source.length() > (leastCompressSize << 10);
}
return true;
}

private int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}
private int pack(byte[] bytes, int offset, int length, boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}

int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
}
return value;
}
return value;
}

private byte[] toByteArray(InputStream is) {
if (is == null) {
return new byte[0];
}
private byte[] toByteArray(InputStream is) {
if (is == null) {
return new byte[0];
}

ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int read;
byte[] data = new byte[4096];

try {
while ((read = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, read);
}
} catch (Exception ignored) {
return new byte[0];
} finally {
try {
buffer.close();
} catch (IOException ignored) {
}
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

byte[] data = new byte[3];

try {
if (is.read(data, 0, 3) != -1) {
buffer.write(data, 0, 3);
} else {
return new byte[0];
}
} catch (Exception e) {
return new byte[0];
} finally {
try {
buffer.close();
} catch (IOException ignored) {
}
}

return buffer.toByteArray();
}
return buffer.toByteArray();
}
}
2 changes: 1 addition & 1 deletion library/src/main/java/top/zibin/luban/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ File compress() throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();

if (Checker.SINGLE.isJPG(srcImg.open())) {
tagBitmap = rotatingImage(tagBitmap, Checker.SINGLE.getOrientation(srcImg.open()));
tagBitmap = rotatingImage(tagBitmap, Checker.SINGLE.getOrientation(srcImg.getPath()));
}
tagBitmap.compress(focusAlpha ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.JPEG, 60, stream);
tagBitmap.recycle();
Expand Down