浏览代码

add `getOrientation` method in engine

郑梓斌 6 年之前
父节点
当前提交
bc3f3d4c0d

+ 1 - 1
build.gradle

@@ -6,7 +6,7 @@ buildscript {
         google()
     }
     dependencies {
-        classpath('com.android.tools.build:gradle:3.1.2') {
+        classpath('com.android.tools.build:gradle:3.1.3') {
             force = true
         }
 

+ 1 - 5
library/build.gradle

@@ -27,8 +27,4 @@ android {
     }
 }
 
-dependencies {
-    testImplementation 'junit:junit:4.12'
-    implementation 'com.android.support:appcompat-v7:27.1.1'
-    implementation "com.android.support:exifinterface:27.1.1"
-}
+dependencies {}

+ 129 - 0
library/src/main/java/top/zibin/luban/Checker.java

@@ -1,14 +1,19 @@
 package top.zibin.luban;
 
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.logging.Logger;
 
 enum Checker {
   SINGLE;
 
+  private final String TAG = "Luban";
+
   private static List<String> format = new ArrayList<>();
   private static final String JPG = "jpg";
   private static final String JPEG = "jpeg";
@@ -16,6 +21,8 @@ enum Checker {
   private static final String WEBP = "webp";
   private static final String GIF = "gif";
 
+  private final byte[] JPEG_SIGNATURE = new byte[]{(byte) 0xFF, (byte) 0xD8, (byte) 0xFF};
+
   static {
     format.add(JPG);
     format.add(JPEG);
@@ -43,6 +50,113 @@ enum Checker {
     return suffix.contains(JPG) || suffix.contains(JPEG);
   }
 
+  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);
+  }
+
+  /**
+   * Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
+   */
+  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(String path) {
     if (TextUtils.isEmpty(path)) {
       return ".jpg";
@@ -58,4 +172,19 @@ enum Checker {
     }
     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;
+  }
 }

+ 1 - 1
library/src/main/java/top/zibin/luban/Engine.java

@@ -3,7 +3,7 @@ package top.zibin.luban;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Matrix;
-import android.support.media.ExifInterface;
+import android.media.ExifInterface;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;