From 61140a86a729bbaaf240e14e546cbf9fafd4528f Mon Sep 17 00:00:00 2001 From: jalen Date: Wed, 19 Sep 2018 18:45:07 +0800 Subject: [PATCH] OOM fixed --- .../main/java/top/zibin/luban/Checker.java | 260 +++++++----------- .../src/main/java/top/zibin/luban/Engine.java | 2 +- 2 files changed, 93 insertions(+), 169 deletions(-) diff --git a/library/src/main/java/top/zibin/luban/Checker.java b/library/src/main/java/top/zibin/luban/Checker.java index 698a4a8..69cf83d 100644 --- a/library/src/main/java/top/zibin/luban/Checker.java +++ b/library/src/main/java/top/zibin/luban/Checker.java @@ -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; @@ -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(); + } } diff --git a/library/src/main/java/top/zibin/luban/Engine.java b/library/src/main/java/top/zibin/luban/Engine.java index 1d6b984..0fcb9d2 100644 --- a/library/src/main/java/top/zibin/luban/Engine.java +++ b/library/src/main/java/top/zibin/luban/Engine.java @@ -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();