我有一个在Android 4.0及以上版本上开发的应用程序。 (该应用程序不支持4.0以下的Android版本[冰淇淋三明治])。
问题与各种图像(例如 jpeg 或 png )格式的(打印)DPI 有关。
这个问题与屏幕 DPI 或各种 Android 设备的尺寸无关。它也与在设备上以屏幕尺寸显示位图无关。
我使用以下代码加载“位图”中的图像文件。然后我使用 jpegCompression 将其裁剪并保存为 JPEG 格式的另一个文件。我已经能够通过以下代码执行此操作,但无法获取加载的 DPI 或设置保存的图像文件的 DPI。
所以我有两个问题。
1) 在“位图”中加载 JPEG 文件之后或同时,如何从 JPEG 文件中获取(打印)DPI?
2)保存新生成的“位图”时,如何在 JPEG 文件中再次设置 DPI?
以下是部分代码供参考。
FileInputStream inputStream = new FileInputStream(theSourcePhotoFilePathName);
Bitmap bitmap = null;
BitmapRegionDecoder decoder = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inDensity = 300; // Tried this but not working.
try {
decoder = BitmapRegionDecoder.newInstance(in, false);
bitmap = decoder.decodeRegion(region, options); // the region has cropping coordinates.
} catch (IllegalArgumentException e){
Log.d("First Activity", "Failed to recycle bitmap for rect=" + region, e);
} catch (IOException e) {
Log.d("First Activity", "Failed to decode into rect=" + region, e);
} finally {
if (decoder != null) decoder.recycle();
}
inputStream.close();
inputStream = null;
FileOutputStream fos = new FileOutputStream( theTargetTempFolderDestFilePath );
bitmap.compress(CompressFormat.JPEG, jpegCompressionRatio, fos);
fos.flush();
fos.close();
fos = null;
我尝试通过谷歌搜索从 stackoverflow 和其他网站查找,但无法获得正确的相关答案。所以我决定在这个论坛上提问。
欢迎您的提示和建议。
桑杰。
为了方便这里准备了复制粘贴方法:
public static void saveBitmapToJpg(Bitmap bitmap, File file, int dpi) throws IOException {
ByteArrayOutputStream imageByteArray = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, imageByteArray);
byte[] imageData = imageByteArray.toByteArray();
setDpi(imageData, dpi);
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(imageData);
fileOutputStream.close();
}
private static void setDpi(byte[] imageData, int dpi) {
imageData[13] = 1;
imageData[14] = (byte) (dpi >> 8);
imageData[15] = (byte) (dpi & 0xff);
imageData[16] = (byte) (dpi >> 8);
imageData[17] = (byte) (dpi & 0xff);
}
保存的文件将正确设置图像 DPI值:
您指的是作为 JPEG 文件一部分写入的 DPI 元数据吗?我最近一直在努力解决这个问题,但想出了一个解决方案。如果您已经解决了这个问题,这个答案可以帮助其他遇到同样问题的人。
当位图在 Android 中被压缩为 JPEG 时,它会以 JFIF 段格式保存。请参阅此处的文章(http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format)。我还附上了在十六进制编辑器中打开的 Android jpeg 图像的屏幕截图,以便您可以看到它是如何匹配的。
要编辑该值,您需要首先创建一个 byte[] 数组来存储 Bitmap.compress()。 这是我的代码的一部分,我就是这样做的(输入是源位图)。
ByteArrayOutputStream uploadImageByteArray = new ByteArrayOutputStream();
input.compress(Bitmap.CompressFormat.JPEG, 100, uploadImageByteArray);
byte[] uploadImageData = uploadImageByteArray.toByteArray();
基于JFIF结构,需要编辑字节数组中的第13、14、15、16、17号索引。第 13 个指定密度类型,第 14 和 15 个指定 X 分辨率,第 16 和 17 个指定 Y 分辨率。就我而言,我将元数据中的 X 和 Y 分辨率更改为 500 dpi。这转换为 0000 0001 1111 0100,即十六进制的 1F4。然后,我将字节 [] 写入文件,将其从手机复制到计算机,并在查看图像属性时验证详细信息是否存在。
uploadImageData[13] = 00000001;
uploadImageData[14] = 00000001;
uploadImageData[15] = (byte) 244
uploadImageData[16] = 00000001;
uploadImageData[17] = (byte) 244
File image = new File(Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
.getAbsolutePath() + "/meta Images/", imageFileName);
FileOutputStream sdCardOutput = new FileOutputStream(image);
sdCardOutput.write(uploadImageData);
注意: Java 使用有符号字节系统,您无法输入任何高于 127 的二进制值,否则编译器会向您咆哮。我在输入 F4 作为字节时遇到了这个问题。解决方案是将您的值转换为十进制,然后使用(字节)强制转换。
希望这有帮助!
给出的答案是关于如何设置 dpi。为了获取图像的 dpi:
final ImageInfo imageInfo = Sanselan.getImageInfo(image_file);
final int physicalWidthDpi = imageInfo.getPhysicalWidthDpi();
final int physicalHeightDpi = imageInfo.getPhysicalHeightDpi();
gradle依赖:
implementation group: 'org.apache.sanselan', name: 'sanselan', version: '0.97-incubator'
因为 ExifInterface.TAG_X_RESOLUTION 是有理值。 你应该使用
ExifInterface.setAttribute(ExifInterface.TAG_X_RESOLUTION, "300/1")
值中的 /1 对我有用。
请考虑不要仅仅修改图像的字节数据,因为这可能会导致ExifInterface无法读取图像的Exif