package com.doumee.lib_coremodel.util.luban; import android.graphics.BitmapFactory; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; enum Checker { SINGLE; private static final String TAG = "Luban"; private static final String JPG = ".jpg"; 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; } 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; } 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; } // 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; } 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; } 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; } return value; } 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) { } } return buffer.toByteArray(); } }