需要 25 秒以上才能将位图从相机保存到 Phone
Takes 25+ Seconds To Save Bitmap From Camera To Phone
我正在制作相机应用程序。
由于某些手机不写入 EXIF 方向数据,因此在获得正确方向方面存在许多问题。因此,我得到位图,保存它(因为我认为我不应该从字节 [] 中读取 EXIF 数据),然后旋转位图,然后保存在原始文件上。
有效,方向问题已解决。问题是我在某些顶级手机上花费了 25 秒或更长时间。你能告诉我为什么我的代码这么慢,或者告诉我如何找到问题吗?
注意:如果我只保存一次图像(即方向错误),则只需要几秒钟。
这是我的图像捕获回调:
private Camera.PictureCallback pictureCallback = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d("EditPhotoFragment", "Error creating media file, check storage permissions");
return;
}
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.flush();
fos.close();
orientPicture(pictureFile);
//TODO async
galleryAddPic(pictureFile);
} catch (FileNotFoundException e) {
Log.d("EditPhotoFragment", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("EditPhotoFragment", "Error accessing file: " + e.getMessage());
}
}
};
这是我定位并重新保存图像的位置:
private Bitmap orientPicture(File pictureFile)
{
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath());
Uri uri = Uri.parse(pictureFile.toString());
ExifInterface exif = null;
try{
exif = new ExifInterface(uri.getPath());
}catch (Exception e)
{
e.printStackTrace();
}
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Matrix matrix = new Matrix();
int rotationInDegrees = 0;
//If the orientation tag is missing need to manually rotate it by the 'default' camera
//orientation and if its front facing need to do 360 - the camera rotation value
if(exifOrientation == ExifInterface.ORIENTATION_UNDEFINED)//All phones in this bucket can go fuck themselves
{
Camera.CameraInfo info = new Camera.CameraInfo();
if(_cameraPreview.isBackFacing())
{
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
}else
{
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
}
rotationInDegrees = info.orientation; //set it to the default camera orientation
}else
{
rotationInDegrees = exifToDegrees(exifOrientation);
if(!_cameraPreview.isBackFacing())//handle mirroring of front camera
{
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
rotationInDegrees = 360 - rotationInDegrees; //For the front camera doing 360 - gets the right orientation
}
}
matrix.preRotate(rotationInDegrees);
if(!_cameraPreview.isBackFacing())//mirror it
{
matrix.preScale(1,-1);
}
Bitmap adjustedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//This saves the proper image over top if it
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
adjustedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
fos.write(byteArray);
fos.flush();
fos.close();
}catch(Exception e)
{
e.printStackTrace();
}
return adjustedBitmap;
}
解决方案
正如我所建议的那样,我应该阅读 exif 数据,由于这个原因,我不需要外部库就可以做到这一点:
Can you advise why my code is so slow
可能出于其他原因,您正在将图像写入文件,从文件中重新读取同一图像,进行转换,然后将图像写回文件。那会花很多时间。
Note: If I only save the image once (i.e. with the wrong orientation) it only takes a couple seconds.
那是因为你做的工作少了很多,只包括 ~33% 的磁盘 I/O,而且磁盘 I/O 会变慢。
since I don't think I should read EXIF data from the byte[]
如果您在小时候受到 byte[]
恶意攻击,我深表歉意。但是,如果您想要更好的性能,您将不得不从图像的现有内存副本中读取 EXIF 数据。
我正在制作相机应用程序。
由于某些手机不写入 EXIF 方向数据,因此在获得正确方向方面存在许多问题。因此,我得到位图,保存它(因为我认为我不应该从字节 [] 中读取 EXIF 数据),然后旋转位图,然后保存在原始文件上。
有效,方向问题已解决。问题是我在某些顶级手机上花费了 25 秒或更长时间。你能告诉我为什么我的代码这么慢,或者告诉我如何找到问题吗?
注意:如果我只保存一次图像(即方向错误),则只需要几秒钟。
这是我的图像捕获回调:
private Camera.PictureCallback pictureCallback = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null){
Log.d("EditPhotoFragment", "Error creating media file, check storage permissions");
return;
}
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.flush();
fos.close();
orientPicture(pictureFile);
//TODO async
galleryAddPic(pictureFile);
} catch (FileNotFoundException e) {
Log.d("EditPhotoFragment", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("EditPhotoFragment", "Error accessing file: " + e.getMessage());
}
}
};
这是我定位并重新保存图像的位置:
private Bitmap orientPicture(File pictureFile)
{
Bitmap bitmap = BitmapFactory.decodeFile(pictureFile.getAbsolutePath());
Uri uri = Uri.parse(pictureFile.toString());
ExifInterface exif = null;
try{
exif = new ExifInterface(uri.getPath());
}catch (Exception e)
{
e.printStackTrace();
}
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Matrix matrix = new Matrix();
int rotationInDegrees = 0;
//If the orientation tag is missing need to manually rotate it by the 'default' camera
//orientation and if its front facing need to do 360 - the camera rotation value
if(exifOrientation == ExifInterface.ORIENTATION_UNDEFINED)//All phones in this bucket can go fuck themselves
{
Camera.CameraInfo info = new Camera.CameraInfo();
if(_cameraPreview.isBackFacing())
{
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
}else
{
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
}
rotationInDegrees = info.orientation; //set it to the default camera orientation
}else
{
rotationInDegrees = exifToDegrees(exifOrientation);
if(!_cameraPreview.isBackFacing())//handle mirroring of front camera
{
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
rotationInDegrees = 360 - rotationInDegrees; //For the front camera doing 360 - gets the right orientation
}
}
matrix.preRotate(rotationInDegrees);
if(!_cameraPreview.isBackFacing())//mirror it
{
matrix.preScale(1,-1);
}
Bitmap adjustedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//This saves the proper image over top if it
try
{
FileOutputStream fos = new FileOutputStream(pictureFile);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
adjustedBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
fos.write(byteArray);
fos.flush();
fos.close();
}catch(Exception e)
{
e.printStackTrace();
}
return adjustedBitmap;
}
解决方案 正如我所建议的那样,我应该阅读 exif 数据,由于这个原因,我不需要外部库就可以做到这一点:
Can you advise why my code is so slow
可能出于其他原因,您正在将图像写入文件,从文件中重新读取同一图像,进行转换,然后将图像写回文件。那会花很多时间。
Note: If I only save the image once (i.e. with the wrong orientation) it only takes a couple seconds.
那是因为你做的工作少了很多,只包括 ~33% 的磁盘 I/O,而且磁盘 I/O 会变慢。
since I don't think I should read EXIF data from the byte[]
如果您在小时候受到 byte[]
恶意攻击,我深表歉意。但是,如果您想要更好的性能,您将不得不从图像的现有内存副本中读取 EXIF 数据。