I want to capture image from camera and store it in sqlite. I resize it before saving.
I use this code it is work but i get a blurring image when i get a fullscreen image wen i display it.
public Bitmap resizeBitmap(Bitmap bitmap) {
int reqWidth = 900;
int reqHeight = 900;
RequestSizeOptions options = null;
try {
if (reqWidth > 0 && reqHeight > 0 && (options == RequestSizeOptions.RESIZE_FIT ||options == RequestSizeOptions.RESIZE_INSIDE || options == RequestSizeOptions.RESIZE_EXACT || options ==RequestSizeOptions.RESIZE_CENTRE_CROP)) {
Bitmap resized = null;
if (options == RequestSizeOptions.RESIZE_EXACT) {
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
} else {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scale = Math.max(width / (float) reqWidth, height / (float) reqHeight);
if (scale > 1 || options == RequestSizeOptions.RESIZE_FIT) {
resized = Bitmap.createScaledBitmap(bitmap, (int) (width / scale), (int) (height / scale), false);
}
if (scale > 1 || options == RequestSizeOptions.RESIZE_CENTRE_CROP) {
int smaller_side = (height-width)>0?width:height;
int half_smaller_side = smaller_side/2;
Rect initialRect = new Rect(0,0,width,height);
Rect finalRect = new Rect(initialRect.centerX()-half_smaller_side,initialRect.centerY()-half_smaller_side,
initialRect.centerX()+half_smaller_side,initialRect.centerY()+half_smaller_side);
bitmap = Bitmap.createBitmap(bitmap, finalRect.left, finalRect.top, finalRect.width(), finalRect.height(), null, true);
//keep in mind we have square as request for cropping, otherwise - it is useless
resized = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
}
}
if (resized != null) {
if (resized != bitmap) {
bitmap.recycle();
}
return resized;
}
}
} catch (Exception e) {
Log.w("AIC", "Failed to resize cropped image, return bitmap before resize", e);
}
return bitmap;
This is the code, i use resize in this function. these function are in model class.
this.image = bitmapToString(resizeBitmap(image));
private static String bitmapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
return Base64.encodeToString(b, Base64.DEFAULT);
}
the camera intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 1);
NB: I save a image in sqlite and i display it on fullsceen.
In my App i need to enable the user to upload 6 images as max from gallery after resize the images to Bitmaps, i have finished the selecting and resizing part successfully as shown below code and store the results in array of bitmaps imageslist .
My question is How to upload my bitmaps array using Retrofit MultipartBody ?? all the topics of Retrofit talking about file upload via file path like the answer of this question which i can't upload the files directly before resize
Retrofit Uploading multiple images to a single key
This is my code :
private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
if (maxHeight > 0 && maxWidth > 0) {
int width = image.getWidth();
int height = image.getHeight();
float ratioBitmap = (float) width / (float) height;
float ratioMax = (float) maxWidth / (float) maxHeight;
int finalWidth = maxWidth;
int finalHeight = maxHeight;
if (ratioMax > 1) {
finalWidth = (int) ((float)maxHeight * ratioBitmap);
} else {
finalHeight = (int) ((float)maxWidth / ratioBitmap);
}
image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
return image;
} else {
return image;
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ConstantsCustomGallery.REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
//The array list has the image paths of the selected images
ArrayList<Image> images = data.getParcelableArrayListExtra(ConstantsCustomGallery.INTENT_EXTRA_IMAGES);
for (int i = 0; i < images.size(); i++) {
Uri uri = Uri.fromFile(new File(images.get(i).path));
Bitmap bm = BitmapFactory.decodeFile(images.get(i).path);
Bitmap resized = resize(bm,512,512);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
// ignore below line
//String encodedImage = Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT);
imageslist.add(resized);
// ignore below lines
//TextSliderView textSliderView = new TextSliderView(uploadimages.this);
//textSliderView.image(new File(images.get(i).path));
//mslider.addSlider(textSliderView);
}
}
Any help will be much appreciated
I have a function to send a file (picture from camera or gallery) to a WebService.
I would like to reduce the image size of fileUri before post (50% per example).
The file is a gallery or camera image.
This is my postFile function :
public static void postFile(Context context, String url, String fileUri, AsyncHttpResponseHandler responseHandler) {
if (myCookieStore == null)
{
myCookieStore = new PersistentCookieStore(context);
client.setCookieStore(myCookieStore);
}
File myFile = new File(Uri.parse(fileUri).getPath());
RequestParams params = new RequestParams();
try {
params.put("profile_picture", myFile);
} catch(FileNotFoundException e) {
Log.d("error", "error catch");
}
Log.d("absolute url", "" + "*" + getAbsoluteUrl(url) + "*");
client.post(context, getAbsoluteUrl(url), params, responseHandler);
}
How can I do that ?
There is this library, that can compress your images to kb from mb, it is very powerful i have used it alot of times, it works file uploads are superfast. link
Snippet : compressedImageFile = Compressor.getDefault(this).compressToFile(actualImageFile);
It internally uses google webp format, WebP is a modern image format that provides superior lossless and lossy compression for images on the web. Using WebP, webmasters and web developers can create smaller, richer images that make the web faster.
The library is great at size compression, it does a really good job, at large files that was based on my observations, like 2mb up, however there are some memory leaks that you need to address, i solved mine by using leak canary , though every developer should always use it. Overall it is awesome fork it and use as please.
I used this code in many projects and always it gives me good results, i remember if i choose a image having size of 5-7MB(image from 12/13 MP camera) this code returns an image of size 1MB or less than 2MB.
public static boolean validateUri(Uri uri) {
if (uri == null)
return false;
else {
String path = uri.getPath();
return !(uri.equals(Uri.EMPTY) || path == null || path.equals("null"));
}
}
First we need a full image and rotate if needed.
public static Bitmap getFullSizeImage(Context context, Uri uri) {
String filePath;
if (validateUri(uri) && uri.toString().contains("file"))
filePath = uri.getPath();
else
filePath = getRealPathFromURI(context, uri, MediaStore.Images.Media.DATA);
if (filePath == null)
return null;
try {
int rotation = 0;
ExifInterface exifInterface = new ExifInterface(filePath);
int exifRotation = exifInterface.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
if (exifRotation != ExifInterface.ORIENTATION_UNDEFINED) {
switch (exifRotation) {
case ExifInterface.ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotation = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotation = 90;
break;
}
}
Matrix matrix = new Matrix();
matrix.setRotate(rotation);
// you can use other than 400 as required width/height
Bitmap sourceBitmap = getBitmapFromPath(400, filePath);
if (sourceBitmap == null)
return null;
return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(),
sourceBitmap.getHeight(), matrix, true);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Now we need a real path from URI
public static String getRealPathFromURI(Context context, Uri contentUri, String type) {
Cursor cursor = null;
String path = null;
try {
// String[] proj = { MediaStore.Images.Media.DATA };
String[] projection = {type};
cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
if (cursor == null)
return null;
int columnIndex = cursor.getColumnIndexOrThrow(type);
cursor.moveToFirst();
path = cursor.getString(columnIndex);
// we choose image from drive etc.
if (path == null)
path = getDocumentRealPathFromUri(context, contentUri);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return path;
}
If we choose a picture from drive etc. we still need a real path of given URI
public static String getDocumentRealPathFromUri(Context context, Uri contentUri) {
Cursor cursor = context.getContentResolver().query(contentUri, null,
null, null, null);
if (cursor == null)
return null;
cursor.moveToFirst();
String documentId = cursor.getString(0);
documentId = documentId.substring(documentId.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ",
new String[]{documentId}, null);
if (cursor == null)
return null;
cursor.moveToFirst();
String path = cursor.getString(cursor
.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
return path;
}
Now we've a real path of selected image so we can get a bitmap from this path using sample size
public static Bitmap getBitmapFromPath(int size, String realPathFromURI) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(realPathFromURI, options);
options.inSampleSize = calculateInSampleSizeUsingPower2(options, size, size);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(realPathFromURI, options);
}
public static int calculateInSampleSizeUsingPower2(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth)
inSampleSize *= 2;
}
return inSampleSize;
}
At this point we've a compressed bitmap, further more we can again compress this bitmap if we perform Base64 operation on a given bitmap.
public static String convertToBase64(Bitmap bitmap) {
if (bitmap == null)
return null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)) {
String base64 = encodeToString(byteArrayOutputStream.toByteArray(), DEFAULT);
try {
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return base64;
}
return null;
}
On your sever end you can decode Base64 and convert back to file stream and save your image.
Example
Bitmap bitmap = getFullSizeImage(context, selectedPhotoUri);
if(bitmap != null){
String base64Image = convertToBase64(bitmap);
if (base64Image != null) {
RequestParams params = new RequestParams();
try {
params.put("title", "your_image_name");
params.put("profile_picture", base64Image);
} catch(FileNotFoundException e) {
Log.d("error", "error catch");
}
}
}
Note
If you don't want to perform Base64 you can use your bitmap to convert into stream and send it to your server.
Use this one to change image width and height
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
matrix, false);
return resizedBitmap;
}
you can use this one for change the size ...This is the Best Example.....
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=70;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
Try this function.It will reduce the size of the bitmap to 512 if its width or height is greater than 512
public static Bitmap resizeBitmap(Bitmap bm) {
if (bm.getWidth() > maxSize || bm.getHeight() > maxSize) {
if (bm.getWidth() > bm.getHeight()) {
newWidth = maxSize;
newHeight = (bm.getHeight() * maxSize) / bm.getWidth();
bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true);
return bm;
} else {
newHeight = maxSize;
newWidth = (bm.getWidth() * maxSize) / bm.getHeight();
bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true);
return bm;
}
}
return bm;
}
You just have to pass the bitmap to this method.
The method to get the bitmap from URI is
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
options);
If the camera image is JPEG, you can use the Bitmap compression method, like:
Bitmap bitmap = BitmapFactory.decodeStream(...uri);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
int compression_factor = 50; // represents 50% compression
bitmap.compress(Bitmap.CompressFormat.JPEG, compression_factor, baos);
byte[] image = baos.toByteArray();
// now update web service asynchronously...
...
} finally {
baos.close();
}
Convert the image into bitmap then use below method
public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
float scaleX = newWidth / (float) bitmap.getWidth();
float scaleY = newHeight / (float) bitmap.getHeight();
float pivotX = 0;
float pivotY = 0;
Matrix scaleMatrix = new Matrix();
scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);
Canvas canvas = new Canvas(scaledBitmap);
canvas.setMatrix(scaleMatrix);
canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
I am converting image to Base64 to send it to the server, But the converted string is a huge string. If the converted image is ~100kb then the converted base64 value string is ~1mb...
My code...
protected String doInBackground(Void...arg0) {
Cursor cursor = mydb.getDat1();
//fetching the image location
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
for( int i=0 ; i< 1 ; i++ )
{
if( cursor.getColumnName(i) != null )
{
try
{
if( cursor.getString(i) != null )
{
//saving image to bitmap
Bitmap bitmap = BitmapFactory.decodeFile(cursor.getString(cursor.getColumnIndex(DBHelper.PHOTO)));
//converting it to base64
String en= encodeToBase64( resize(bitmap,1080,1920), Bitmap.CompressFormat.JPEG,100);
Log.d("base",en);
//inserting it to table pic
mydb.insertpic(cursor.getInt(1),en);
}
}
catch( Exception ignored)
{
}
}
}
cursor.moveToNext();
}
cursor.close();
mydb.updatebin();
return null;
}
private static Bitmap resize(Bitmap image, int maxWidth, int maxHeight) {
//for conerting images to lower resolution
if (maxHeight > 0 && maxWidth > 0) {
int width = image.getWidth();
int height = image.getHeight();
float ratioBitmap = (float) width / (float) height;
float ratioMax = (float) maxWidth / (float) maxHeight;
int finalWidth = maxWidth;
int finalHeight = maxHeight;
if (ratioMax > 1) {
finalWidth = (int) ((float)maxHeight * ratioBitmap);
} else {
finalHeight = (int) ((float)maxWidth / ratioBitmap);
}
image = Bitmap.createScaledBitmap(image, finalWidth, finalHeight, true);
return image;
} else {
return image;
}
}
public static String encodeToBase64(Bitmap image, Bitmap.CompressFormat compressFormat, int quality)
{
//converting image to base 64
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
image.compress(compressFormat, quality, byteArrayOS);
return Base64.encodeToString(byteArrayOS.toByteArray(), Base64.DEFAULT);
}
How can i resolve this issue.?
This is the code:
Code to fetch image :
if (requestCode == TAKE_PHOTO_CODE && resultCode == RESULT_OK) {
final Uri imageUri = data.getData();
final InputStream imageStream = getContentResolver().openInputStream(imageUri);
final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
String encodedImage = encodeImage(selectedImage);
}
Try to compress and then convert(Bitmap)
private String encodeImage(Bitmap bm)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG,100,baos);
byte[] b = baos.toByteArray();
String encImage = Base64.encodeToString(b, Base64.DEFAULT);
return encImage;
}
My guess is that the encondeToBase64() is creating a large image file, since you resize the original image to 1920x1080 and convert to a jpeg with quality 100, and then the file then grows around 1.333... times in size when you convert to base64.
I am implementing an android program that allows users to upload photos from their device gallery to an ImageView. saving it in the cloud. My code works fine with small photos, but bigger photos caused the application to stop. I'm getting this error:
Bitmap too large to be uploaded into a texture (4128x2322, max=4096x4096)
I tried to resize the uploaded photo before displaying it using suggestions from previous questions, but they didn't work. I am not sure what the problem with my code is.
Any help would be appreciated. Here is the code from my last attempt:
{
// omitted code segment from onCreate...
browseButton = ((Button) findViewById(R.id.browse_button));
browseButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"Select Picture"), SELECT_PICTURE);
}
}
);
}
//end on create
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
if (requestCode == SELECT_PICTURE)
{
Uri selectedImageUri = data.getData();
selectedImagePath = getPath(selectedImageUri);
System.out.println("Image Path : " + selectedImagePath);
Bitmap bitmap = BitmapFactory.decodeFile(selectedImagePath);
// Convert it to byte
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// Compress image to lower quality scale 1 - 100
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
image = stream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
Bitmap toyImageScaled = Bitmap.createScaledBitmap(bitmap, 200, 200
* bitmap.getHeight() / bitmap.getWidth(), false);
// Override Android default landscape orientation and save portrait
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap rotatedScaledToyImage = Bitmap.createBitmap(toyImageScaled, 0,
0, toyImageScaled.getWidth(), toyImageScaled.getHeight(),
matrix, true);
toyPreview.setImageBitmap(bitmap);
}
}
}
public String getPath(Uri uri)
{
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
You're still showing the big image at:
toyPreview.setImageBitmap(bitmap);
You should be showing the scaled image, toyImageScaled or rotatedScaledToyImage.
I think you should use the examples of the documentation, and use InSampleSize.
see this : http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
From DOCS:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}