Losing bitmap image quality - java

I'm getting an image from gallery into a layout , then I'm getting the bitmap of that layout by using getBitmap(), after getting bitmap I'm saving the image into device storage by using saveImage().
After getting bitmap and saving the bitmap, the quality and pixel of that bitmap reduces too much as shown in the pictureSaved image AND Orignal image
Here is the code for getting and saving bitmap
private Bitmap getBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
Toast.makeText(this, "Something Wrong", Toast.LENGTH_SHORT).show();
return null;
}
Bitmap lastimage = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
//2048x2048 resolution
int newWidth = 2048;
int newHeight = 2048;
int width = lastimage.getWidth();
int height = lastimage.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(lastimage, 0, 0, width, height, matrix, true);
lastimage.recycle();
saveImage(resizedBitmap);
return resizedBitmap;
}
For Saving:
private void saveImage (Bitmap finalBitmap) {
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/NewFolder");
myDir.mkdirs();
String fname = "Image-.png";
File file = new File(myDir, fname);
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Thanks for anyone's help.

Related

I get the following error when I use an ExifInterface in Android API 29

I am using API 29 with version 3.5.3 of gradle.
The error is as follows:
ExifInterface: Invalid image: ExifInterface got an unsupported image format file(ExifInterface supports JPEG and some RAW image formats only) or a corrupted JPEG file to ExifInterface.
java.io.IOException: Invalid byte order: 0
at android.media.ExifInterface.readByteOrder(ExifInterface.java:3128)
at android.media.ExifInterface.isOrfFormat(ExifInterface.java:2443)
at android.media.ExifInterface.getMimeType(ExifInterface.java:2321)
at android.media.ExifInterface.loadAttributes(ExifInterface.java:1755)
at android.media.ExifInterface.<init>(ExifInterface.java:1449)
This is the code that generates the error:
public static byte[] compressImageToBytes(Uri imageUri, int quality, int height, int width, Context context, Bitmap.CompressFormat format) throws IOException {
Bitmap bitmap;
ExifInterface exif;
if (Build.VERSION.SDK_INT > 28) {
InputStream image = context.getContentResolver().openInputStream(imageUri);
bitmap = BitmapFactory.decodeStream(image);
exif = new ExifInterface(image);
image.close();
}
else {
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), imageUri);
exif = new ExifInterface(getImageRealPathFromURI(context, imageUri));
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
} else if (orientation == 3) {
matrix.postRotate(180);
} else if (orientation == 8) {
matrix.postRotate(270);
}
Bitmap compressed = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Bitmap scaledBitmap = scaleBitmap(compressed, width, height);
scaledBitmap = overlayBitmapToCenter(Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888), scaledBitmap);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
scaledBitmap.compress(format, quality, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
Could someone guide me on how to resolve this error, thanks.

picture rotated 90 degrees when copy the picture from URI to file

I was trying to copy a picture from URI to a file path. Then I read the picture from the path, but the picture I got was rotated 90 degrees down. Below is my function. Anybody can help on this?
public boolean copyPicture(Context context, Uri source, String dest) {
boolean result = false;
int bytesum = 0;
int byteread = 0;
File destFile = new File(dest);
String scheme = source.getScheme();
if (ContentResolver.SCHEME_CONTENT.equals(scheme)
|| ContentResolver.SCHEME_FILE.equals(scheme)) {
InputStream inStream = null;
try {
inStream = context.getContentResolver().openInputStream(source);
if (!destFile.exists()) {
result = destFile.createNewFile();
}
if (result) {
FileOutputStream fs = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
fs.flush();
fs.close();
}
} catch (Exception e) {
e.printStackTrace();
result = false;
}
}
return result;
}
EXIF INTERFACE is the answer. It allows you to read specified attributes from a image file.
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
try {
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
Bitmap correctBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mat, true);
bitmap=correctBmp;
}
catch(Exception e){
}

Why i cannot show my byte[] image after converting it from bitmap?

I'm trying to write a method that accepts an image(Bitmap) and returns a byte[] array. finally, I try to write this byte[] array to a folder so I can see the difference, but my byte[] arraycan not displayed, and in addition, it is not scaled down! This is my method:
private byte[] changeSize(Bitmap image) {
byte[] picture;
int width = image.getWidth();
int height = image.getHeight();
int newHeight = 0, newWidth = 0;
if (width > 250 || height > 250) {
if (width > height) { //landscape-mode
newHeight = 200;
newWidth = (newHeight * width) / height;
} else { //portrait-mode
newWidth = 200;
newHeight = (newWidth * height) / width;
}
} else {
Toast.makeText(this, "Something wrong!", Toast.LENGTH_LONG).show();
}
Bitmap sizeChanged = Bitmap.createScaledBitmap(image, newWidth, newHeight, true);
//Convert bitmap to a byte array
int bytes = sizeChanged.getByteCount();
ByteBuffer bb = ByteBuffer.allocate(bytes);
sizeChanged.copyPixelsFromBuffer(bb);
picture = bb.array();
//Write to a hd
picturePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
String fileName = edFile.getText().toString() + "_downscaled" + ".jpg";
File file = new File(picturePath, fileName);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write(picture);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return image;
}
I tried several hours to get my byte[] array visible, but I could simply not do this. Any help or hints to show me where I derail is/are very appreciated.
This was working for me
public static Bitmap byteArraytoBitmap(byte[] bytes) {
return (BitmapFactory.decodeByteArray(bytes, 0, bytes.length));
}
public static byte[] bitmaptoByteArray(Bitmap bmp) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream); //PNG format is lossless and will ignore the quality setting!
byte[] byteArray = stream.toByteArray();
return byteArray;
}
public static Bitmap bitmapFromFile(File file) {
//returns null if could not decode
return BitmapFactory.decodeFile(file.getPath());
}
public static boolean saveImage(Bitmap image, String filePath) {
LogInfo(TAG, "Saving image to: " + filePath);
File file = new File(filePath);
File fileDirectory = new File(file.getParent());
LogInfo(TAG, fileDirectory.getPath());
if (!fileDirectory.exists()) {
if (!fileDirectory.mkdirs()) {
Log.e(TAG, "ERROR CREATING DIRECTORIES");
return false;
}
}
try {
file.createNewFile();
FileOutputStream fo = new FileOutputStream(file);
fo.write(bitmaptoByteArray(image));
fo.flush();
fo.close();
return true;
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}

Camera to nfc - best photoquality

For my application, I need to save a photo, taken from camera of a device, on an 7.7k nfc chip.
In the onActivityResult, I resize the bitmap as here :
String fileName = "original";
String path = Environment.getExternalStorageDirectory() + "/" + fileName + ".jpg";
//Resizing
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap current = BitmapFactory.decodeFile(path);
Bitmap resized = resizeBitMapImage(path,largeur,(int)(largeur*1.8));
with
public static Bitmap resizeBitMapImage(String filePath, int targetWidth, int targetHeight) {
Bitmap bitMapImage = null;
try {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
double sampleSize = 0;
Boolean scaleByHeight = Math.abs(options.outHeight - targetHeight) >= Math.abs(options.outWidth
- targetWidth);
if (options.outHeight * options.outWidth * 2 >= 1638) {
sampleSize = scaleByHeight ? options.outHeight / targetHeight : options.outWidth / targetWidth;
sampleSize = (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
}
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[128];
while (true) {
try {
options.inSampleSize = (int) sampleSize;
Log.v(LOG_TAG,"inSampleSize" + options.inSampleSize);
bitMapImage = BitmapFactory.decodeFile(filePath, options);
break;
} catch (Exception ex) {
try {
sampleSize = sampleSize + 1 ;
} catch (Exception ex1) {
}
}
}
} catch (Exception ex) {
}
return bitMapImage;
}
(Found on SO)
And then, I save it on the chip with :
NdefRecord picRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "image/jpeg".getBytes(), null, byteArray);
When I choose a width of 200, and a compression of 50, the picture takes about 7k, but the quality is quite low. The bitmap is a contact photo.
So my questions :
What should I use as width, height, compression, in order to get the best photo quality (less than 7k?
Should the camera be set on high or low resolution ?
PNG or JPEG compression ?

capture bitmap and add watermark

I trying capture image and set water mark from onActivityResult method is fragment from my code.
Private void savingCapturedImage() {
long date = System.currentTimeMillis();
Date data = new Date(date);
File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera", "mobiliskaita.JPG");
Uri imagePath = Uri.fromFile(file);
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imagePath);
System.out.println("bitmap: " + bitmap.getWidth() + " " + bitmap.getHeight());
file.delete();
bitmap = mark(bitmap, String.valueOf(data), 100, 200, 100, false);
bitmap = mark(bitmap, TheGlobals.partneriaiValue, 100, 310, 100, false);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
bitmap.recycle();
File fileOutput = new File(Environment.getExternalStorageDirectory() + "/DCIM/Camera", photoName());
fileOutput.createNewFile();
FileOutputStream fo = new FileOutputStream(fileOutput);
fo.write(bytes.toByteArray());
fo.flush();
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
private Bitmap mark(Bitmap src, String watermark, int x, int y, int size, boolean underline) {
int w = src.getWidth();
int h = src.getHeight();
Point _p = new Point();
_p.x = x;
_p.y = y;
final float scale = getResources().getDisplayMetrics().density;
int p = (int) (900 * scale + 0.5f);
Bitmap result = Bitmap.createScaledBitmap(src, p, p, true);
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(R.dimen.default_text_size);
paint.setAntiAlias(true);
paint.setUnderlineText(underline);
canvas.drawText(watermark, _p.x, _p.y, paint);
return result;
}
It's working but then i have camer with 8 or more megapixels, i get out of memory expection. Maybe someone can help my solve this problem?
The bitmap from the camera is going to be big, if you're only going to save it as 900x900, then you may have to use another method of reading it (not MediaStore.Images.Media.getBitmap()), one where you can set the inSampleSize: http://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeFile(java.lang.String, android.graphics.BitmapFactory.Options)
You could also recycle src in mark() after you've drawn it to the canvas. At the moment you are creating 2 900x900dp bitmaps, so merging the 2 calls to mark might also help.

Categories