I have an app developed on Android versions 4.0 and above. ( The app does not support Android versions below 4.0 [Ice Cream Sandwich] ).
The question is related to (print) DPI of various images ( for eg. of jpeg or png ) format.
This question does NOT relate to SCREEN DPI or sizes of various Android devices. It is also NOT related to showing the Bitmap on the device in screen size.
I am using the following code to load the image file in 'Bitmap'. Then I have been cropping it and saving it to another file in JPEG format with jpegCompression. I have been able to do this by the following code, but I am unable to get DPI of loaded or set the DPI of saved Image file.
So I have two questions.
1) How can I get the (print) DPI from the JPEG file, after or while loading it in 'Bitmap'?
2) While saving the new generated 'Bitmap', how can I set the DPI again in the JPEG file?
Following is the part of code for reference.
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;
I have tried to find from stackoverflow and from other sites by googling, but could not get the proper related answer. So I have decided to ask it in this forum.
Your hints and suggestions are welcome.
Sanjay.
The given answers are about how to set dpi. In order to get dpi of an image:
final ImageInfo imageInfo = Sanselan.getImageInfo(image_file);
final int physicalWidthDpi = imageInfo.getPhysicalWidthDpi();
final int physicalHeightDpi = imageInfo.getPhysicalHeightDpi();
The gradle dependency: implementation group: 'org.apache.sanselan', name: 'sanselan', version: '0.97-incubator'
Just for convenience here is ready to copy and paste method:
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);
}
saved file will have properly set Image DPI value:
Are you referring to the DPI metaData written as part of the JPEG file? I have struggled with that recently but came up with a solution. If you have already solved it, this answer can help others who run into the same problem.
When a Bitmap is compressed to JPEG in Android, it saves it in a JFIF segment format. Please see article here(http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format). I have also attached a screenshot of an Android jpeg image opened up in a hex editor so you can see how it matches.
To edit the value, you need to first create a byte[] array that will store the Bitmap.compress(). Here is a part of my code where I do just that(input being the source Bitmap).
ByteArrayOutputStream uploadImageByteArray = new ByteArrayOutputStream();
input.compress(Bitmap.CompressFormat.JPEG, 100, uploadImageByteArray);
byte[] uploadImageData = uploadImageByteArray.toByteArray();
Based on the JFIF structure, you need to edit the 13th, 14th, 15th, 16th, and 17th indexes in the byte array. 13th specifying the density type, 14th and 15th the X resolution, and 16th and 17th holding the Y resolution. In my case, I changed it to 500 dpi as the X and Y resolution in the metadata. This translated to 0000 0001 1111 0100 which is 1F4 in hex. I then wrote the byte[] to file, copied it from my phone to my computer, and verified the details were present when viewing the image properties.
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);
NOTE: Java uses a signed byte system and you cannot enter in any binary value above 127 without the compiler barking at you. I ran into this problem inputting F4 as a byte. The solution is to convert your value to decimal and then use a (byte) cast.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With