如何在 Android 中使用完整图像大小(不是缩略图)拍摄照片并将图像压缩为字节?
How to take a photo in Android, using full image size(not thumbnail) and compress the image to bytes?
我不知道我是不是做错了什么,也许我根本没有使用图像,或者我以错误的方式压缩图像,因为当我想将它发送到服务器时,它回复我说大小超过 10 MB 当我的 phone 拍摄照片时 jpg 大约 7-9 MB(在 Edit.java 我有评论说我之前使用缩略图但需要更改它因为我尝试时缩略图质量很差在桌面上查看)
这是我的代码:
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera"></uses-feature>
<provider
android:authorities="cam.com.example.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path"/>
</provider>
file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="/"/>
<external-files-path
name="external_files"
path="/"/>
<cache-path
name="cache"
path="/"/>
<external-cache-path
name="external_cache"
path="/"/>
<files-path
name="files"
path="/"/>
</paths>
Edit.java
btn_image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
REQUEST_IMAGE_CAPTURE = 1;
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
File imageFile = null;
try{
imageFile=getImageFile();
}catch (IOException e){
e.printStackTrace();
}
if(imageFile!=null){
Uri imageUri = FileProvider.getUriForFile(Edit.this,"cam.com.example.fileprovider",imageFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(cameraIntent, REQUEST_IMAGE_CAPTURE);
}
}
} catch (Exception e) {
Toasty.warning(getApplicationContext(), IC, Toast.LENGTH_SHORT, true).show();
}
}
});
public File getImageFile() throws IOException{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageName = "jpg_"+timeStamp+"_";
File storageDir = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(imageName,".jpg",storageDir);
currentImagePath = imageFile.getAbsolutePath();
return imageFile;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
if (imagenString == null) {
File imgFile = new File(currentImagePath);
String path = imgFile.getAbsolutePath();
Bitmap mybitmap = BitmapFactory.decodeFile(path);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mybitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
imagenString = Base64.encodeToString(byteArray, Base64.DEFAULT);
/* **Before I was doing this, but the thumbnail has such a bad quality so needed to change it**
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
imagenString = Base64.encodeToString(byteArray, Base64.DEFAULT);*/
}
}
}
您正在使用用户选择的相机应用拍照。通常,它会保存为 JPEG 图像。 JPEG 图像是压缩图像格式,针对 "real-world" 图像(如照片)进行了优化。
然后您尝试将其全部读入内存。这不是一个好的计划,因为对于全尺寸照片,您可能没有足够的内存来执行此操作。
然后您尝试获取结果 Bitmap
并将其编码为 PNG。 PNG 是一种压缩图像格式,但专为图标和其他艺术品设计。 PNG 格式的照片几乎总是比 JPEG 格式的照片多 space。更糟糕的是,您正试图将其编码为 PNG 并存入内存 — 同样,您可能没有足够的内存来执行此操作。
然后您尝试将编码的 PNG 转换为 base-64。这将比编码后的 PNG 占用更多 space,而且,再一次,您可能没有足够的内存。
我希望您的应用经常崩溃 OutOfMemoryError
。
最好的解决办法是去掉其中的大部分,直接从磁盘上传 JPEG。不载入内存,不转PNG,不转base-64
这是因为您将图像转换为 Base64 编码字符串,这使得数据的大小变大了。
在以下代码中,您使用值 100 进行压缩,100 表示压缩最少且质量高。
mybitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
您可以尝试压缩更多图像,但会稍微降低质量:
mybitmap.compress(Bitmap.CompressFormat.PNG, 70, byteArrayOutputStream);
我不知道我是不是做错了什么,也许我根本没有使用图像,或者我以错误的方式压缩图像,因为当我想将它发送到服务器时,它回复我说大小超过 10 MB 当我的 phone 拍摄照片时 jpg 大约 7-9 MB(在 Edit.java 我有评论说我之前使用缩略图但需要更改它因为我尝试时缩略图质量很差在桌面上查看)
这是我的代码:
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera"></uses-feature>
<provider
android:authorities="cam.com.example.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path"/>
</provider>
file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external"
path="/"/>
<external-files-path
name="external_files"
path="/"/>
<cache-path
name="cache"
path="/"/>
<external-cache-path
name="external_cache"
path="/"/>
<files-path
name="files"
path="/"/>
</paths>
Edit.java
btn_image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
REQUEST_IMAGE_CAPTURE = 1;
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getPackageManager()) != null) {
File imageFile = null;
try{
imageFile=getImageFile();
}catch (IOException e){
e.printStackTrace();
}
if(imageFile!=null){
Uri imageUri = FileProvider.getUriForFile(Edit.this,"cam.com.example.fileprovider",imageFile);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(cameraIntent, REQUEST_IMAGE_CAPTURE);
}
}
} catch (Exception e) {
Toasty.warning(getApplicationContext(), IC, Toast.LENGTH_SHORT, true).show();
}
}
});
public File getImageFile() throws IOException{
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageName = "jpg_"+timeStamp+"_";
File storageDir = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File imageFile = File.createTempFile(imageName,".jpg",storageDir);
currentImagePath = imageFile.getAbsolutePath();
return imageFile;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
if (imagenString == null) {
File imgFile = new File(currentImagePath);
String path = imgFile.getAbsolutePath();
Bitmap mybitmap = BitmapFactory.decodeFile(path);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mybitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
imagenString = Base64.encodeToString(byteArray, Base64.DEFAULT);
/* **Before I was doing this, but the thumbnail has such a bad quality so needed to change it**
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
imagenString = Base64.encodeToString(byteArray, Base64.DEFAULT);*/
}
}
}
您正在使用用户选择的相机应用拍照。通常,它会保存为 JPEG 图像。 JPEG 图像是压缩图像格式,针对 "real-world" 图像(如照片)进行了优化。
然后您尝试将其全部读入内存。这不是一个好的计划,因为对于全尺寸照片,您可能没有足够的内存来执行此操作。
然后您尝试获取结果 Bitmap
并将其编码为 PNG。 PNG 是一种压缩图像格式,但专为图标和其他艺术品设计。 PNG 格式的照片几乎总是比 JPEG 格式的照片多 space。更糟糕的是,您正试图将其编码为 PNG 并存入内存 — 同样,您可能没有足够的内存来执行此操作。
然后您尝试将编码的 PNG 转换为 base-64。这将比编码后的 PNG 占用更多 space,而且,再一次,您可能没有足够的内存。
我希望您的应用经常崩溃 OutOfMemoryError
。
最好的解决办法是去掉其中的大部分,直接从磁盘上传 JPEG。不载入内存,不转PNG,不转base-64
这是因为您将图像转换为 Base64 编码字符串,这使得数据的大小变大了。
在以下代码中,您使用值 100 进行压缩,100 表示压缩最少且质量高。
mybitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
您可以尝试压缩更多图像,但会稍微降低质量:
mybitmap.compress(Bitmap.CompressFormat.PNG, 70, byteArrayOutputStream);