Image orientation fix (#475, #309) (#493)

fix
This commit is contained in:
Alexander Pantyuhov 2016-12-05 02:32:04 +03:00 committed by Nicolas Charpentier
parent fd61e506e5
commit 06dc7ac5a7
2 changed files with 103 additions and 25 deletions

View File

@ -33,4 +33,5 @@ repositories {
dependencies {
compile "com.facebook.react:react-native:0.19.+"
compile "com.google.zxing:core:3.2.1"
compile "com.drewnoakes:metadata-extractor:2.9.1"
}

View File

@ -10,10 +10,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaActionSound;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.media.*;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
@ -21,6 +18,11 @@ import android.util.Base64;
import android.util.Log;
import android.view.Surface;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
@ -30,14 +32,7 @@ import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
@ -493,6 +488,28 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
return byteArray;
}
private byte[] saveImage(InputStream is, Bitmap image) {
byte[] result = null;
try {
result = compress(image, 85);
} catch (OutOfMemoryError e) {
try {
result = compress(image, 70);
} catch (OutOfMemoryError e2) {
e.printStackTrace();
}
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
private byte[] mirrorImage(byte[] data) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
Bitmap photo = BitmapFactory.decodeStream(inputStream);
@ -501,25 +518,80 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
m.preScale(-1, 1);
Bitmap mirroredImage = Bitmap.createBitmap(photo, 0, 0, photo.getWidth(), photo.getHeight(), m, false);
byte[] result = null;
return saveImage(inputStream, mirroredImage);
}
private byte[] rotate(byte[] data, int exifOrientation) {
final Matrix bitmapMatrix = new Matrix();
switch(exifOrientation)
{
case 1:
break;
case 2:
bitmapMatrix.postScale(-1, 1);
break;
case 3:
bitmapMatrix.postRotate(180);
break;
case 4:
bitmapMatrix.postRotate(180);
bitmapMatrix.postScale(-1, 1);
break;
case 5:
bitmapMatrix.postRotate(90);
bitmapMatrix.postScale(-1, 1);
break;
case 6:
bitmapMatrix.postRotate(90);
break;
case 7:
bitmapMatrix.postRotate(270);
bitmapMatrix.postScale(-1, 1);
break;
case 8:
bitmapMatrix.postRotate(270);
break;
default:
break;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
Bitmap decodedBitmap = BitmapFactory.decodeStream(inputStream);
final Bitmap transformedBitmap = Bitmap.createBitmap(
decodedBitmap, 0, 0, decodedBitmap.getWidth(), decodedBitmap.getHeight(), bitmapMatrix, false
);
return saveImage(inputStream, transformedBitmap);
}
private byte[] fixOrientation(byte[] data) {
final Metadata metadata;
try {
result = compress(mirroredImage, 85);
} catch (OutOfMemoryError e) {
try {
result = compress(mirroredImage, 70);
} catch (OutOfMemoryError e2) {
metadata = ImageMetadataReader.readMetadata(
new BufferedInputStream(new ByteArrayInputStream(data)), data.length
);
final ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
final int exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
return rotate(data, exifOrientation);
}
return data;
} catch (IOException | ImageProcessingException | MetadataException e) {
e.printStackTrace();
return data;
}
}
private void rewriteOrientation(String path) {
try {
inputStream.close();
ExifInterface exif = new ExifInterface(path);
exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(ExifInterface.ORIENTATION_NORMAL));
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, e.getMessage());
}
return result;
}
private byte[] compress(Bitmap bitmap, int quality) throws OutOfMemoryError {
@ -593,6 +665,8 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
}
}
data = fixOrientation(data);
camera.stopPreview();
camera.startPreview();
WritableMap response = new WritableNativeMap();
@ -615,6 +689,7 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
return;
}
rewriteOrientation(cameraRollFile.getAbsolutePath());
addToMediaStore(cameraRollFile.getAbsolutePath());
response.putString("path", Uri.fromFile(cameraRollFile).toString());
promise.resolve(response);
@ -633,6 +708,7 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
return;
}
rewriteOrientation(pictureFile.getAbsolutePath());
response.putString("path", Uri.fromFile(pictureFile).toString());
promise.resolve(response);
break;
@ -649,6 +725,7 @@ public class RCTCameraModule extends ReactContextBaseJavaModule
promise.reject(error);
}
rewriteOrientation(tempFile.getAbsolutePath());
response.putString("path", Uri.fromFile(tempFile).toString());
promise.resolve(response);
break;