在我们的应用程序中,用户多年来(大致)使用以下代码上传了数百万张图片:
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(postFilePath, bmOptions);
Bitmap roughBitmap = BitmapFactory.decodeFile(postFilePath, bmOptions);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
roughBitmap.compress(Bitmap.CompressFormat.JPEG, 70, stream);
InputStream fis = new ByteArrayInputStream(stream.toByteArray());
int fileSize = stream.toByteArray().length;
conn.setRequestProperty("Content-Length", Integer.toString(fileSize));
conn.setFixedLengthStreamingMode(fileSize);
...
if (fis != null) {
byte[] buf = new byte[10240];
int read;
while ((read = fis.read(buf)) > 0) {
os.write(buf, 0, read);
totalBytesRead += read;
if (uploadProgressListener != null) {
try {
uploadProgressListener.onBytesUploaded(read);
} catch (Exception e) {
Log.e(e);
}
}
}
fis.close();
}
最近我们发现需要保存上传图像的 Exif
数据。问题是压缩位图时图像 Exif 数据丢失。我想到了使用 ExifInterface
从原始文件中提取这些数据:
ExifInterface oldExif = new ExifInterface(postFilePath);
String value = oldExif.getAttribute(ExifInterface.TAG_DATETIME);
..然后将其添加到 InputStream fis
中,然后继续上传文件。问题是 ExifInterface
无法将 Exif 数据保存到 InputStream。
图片上传到服务器时如何保留图片中的Exif数据?
这不是重复的:
只是为了更深入地阐明,我已经尝试通过使用此方法来使用建议的重复问题
:
public static void copyExif(String originalPath, InputStream newStream) throws IOException {
String[] attributes = new String[]
{
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_DATETIME_DIGITIZED,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
ExifInterface.TAG_FOCAL_LENGTH,
ExifInterface.TAG_GPS_ALTITUDE,
ExifInterface.TAG_GPS_ALTITUDE_REF,
ExifInterface.TAG_GPS_DATESTAMP,
ExifInterface.TAG_GPS_LATITUDE,
ExifInterface.TAG_GPS_LATITUDE_REF,
ExifInterface.TAG_GPS_LONGITUDE,
ExifInterface.TAG_GPS_LONGITUDE_REF,
ExifInterface.TAG_GPS_PROCESSING_METHOD,
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_SUBSEC_TIME,
ExifInterface.TAG_WHITE_BALANCE
};
ExifInterface oldExif = new ExifInterface(originalPath);
ExifInterface newExif = new ExifInterface(newStream);
if (attributes.length > 0) {
for (int i = 0; i < attributes.length; i++) {
String value = oldExif.getAttribute(attributes[i]);
if (value != null)
newExif.setAttribute(attributes[i], value);
}
newExif.saveAttributes();
}
}
.. 但出现异常 java.io.IOException: ExifInterface does not support saving attributes for the current input.
在 newExif.saveAttributes();
之后因为我'我正在尝试将属性保存到 InputStream。我还能怎么做?
最佳答案
我的解决方案:
正如@amuttsch 和@CommonsWare 所建议的,我:
- 将缩放/压缩后的位图保存到临时文件
- 将exif从原文件复制到临时文件
- 将临时文件转换为字节数组并将其发送以上传
.. 然后我发现服务器在生成图像变体时再次剥离了 Exif :-P 但这是服务器人员现在正在努力纠正的另一个故事。
主要代码:
...
// Copy original Exif to scaledBitmap
String tempFilePath = getTempFilePath(postFilePath);
try {
FileOutputStream out = new FileOutputStream(tempFilePath);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 70, out);
copyExif(postFilePath, tempFilePath);
} catch (Exception e) {
e.printStackTrace();
}
// Get stream from temp (exif loaded) file
File tempFile = new File(tempFilePath);
byte[] byteFile = readFile(tempFile);
fis = new ByteArrayInputStream(byteFile);
// Remove the temp file
boolean deleted = tempFile.delete();
// Finalize
int fileSize = byteFile.length;
conn.setRequestProperty("Content-Length", Integer.toString(fileSize));
conn.setFixedLengthStreamingMode(fileSize);
...
getTempFilePath():
private String getTempFilePath(String filename) {
String temp = "_temp";
int dot = filename.lastIndexOf(".");
String ext = filename.substring(dot + 1);
if (dot == -1 || !ext.matches("\\w+")) {
filename += temp;
} else {
filename = filename.substring(0, dot) + temp + "." + ext;
}
return filename;
}
copyExif():
public static void copyExif(String originalPath, String newPath) throws IOException {
String[] attributes = new String[]
{
ExifInterface.TAG_DATETIME,
ExifInterface.TAG_DATETIME_DIGITIZED,
ExifInterface.TAG_EXPOSURE_TIME,
ExifInterface.TAG_FLASH,
ExifInterface.TAG_FOCAL_LENGTH,
ExifInterface.TAG_GPS_ALTITUDE,
ExifInterface.TAG_GPS_ALTITUDE_REF,
ExifInterface.TAG_GPS_DATESTAMP,
ExifInterface.TAG_GPS_LATITUDE,
ExifInterface.TAG_GPS_LATITUDE_REF,
ExifInterface.TAG_GPS_LONGITUDE,
ExifInterface.TAG_GPS_LONGITUDE_REF,
ExifInterface.TAG_GPS_PROCESSING_METHOD,
ExifInterface.TAG_GPS_TIMESTAMP,
ExifInterface.TAG_MAKE,
ExifInterface.TAG_MODEL,
ExifInterface.TAG_ORIENTATION,
ExifInterface.TAG_SUBSEC_TIME,
ExifInterface.TAG_WHITE_BALANCE
};
ExifInterface oldExif = new ExifInterface(originalPath);
ExifInterface newExif = new ExifInterface(newPath);
if (attributes.length > 0) {
for (int i = 0; i < attributes.length; i++) {
String value = oldExif.getAttribute(attributes[i]);
if (value != null)
newExif.setAttribute(attributes[i], value);
}
newExif.saveAttributes();
}
}
读取文件():
public static byte[] readFile(File file) throws IOException {
// Open file
RandomAccessFile f = new RandomAccessFile(file, "r");
try {
// Get and check length
long longlength = f.length();
int length = (int) longlength;
if (length != longlength)
throw new IOException("File size >= 2 GB");
// Read file and return data
byte[] data = new byte[length];
f.readFully(data);
return data;
} finally {
f.close();
}
}
关于Android:上传图像而不丢失 Exif 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44928092/