I have a app that uploads a picture made by the camera and upload it to a server.
But when i try to get it from the server into my imageview it says that the bitmap is to large ( in pixels )
How can i fix this?
new DownloadImageTask(imgProfile)
.execute("http://api.nl/local/index.php?action=get_user_profile_picture&username="
+ SaveSharedPreferences.user.getUsername()
+ "&password="
+ SaveSharedPreferences.user.getPassword()
+ "&user_number="
+ SaveSharedPreferences.user.getUserNumber());
This is my code that i use to process the image to the imageview:
class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
try{
InputStream in = new java.net.URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch(OutOfMemoryError e){
}
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
What you are seeing is the effect of hardware acceleration. The system tries to load an extremely huge bitmap into an image view. If you have hardware acceleration turned on (e.g. via the Manifest) android will try to put the bitmap into an openGL texture, and your image is too big for this. It does not matter if you use JPEG or bitmaps for this, as the final openGL texture will have raw data and thus be a bitmap either way (each pixel is represented as it's own float values).
The only chance you have is to either download the image a lot smaller or resize it on the device. I'd go with the smaller download because it will also save the users's bandwith (and therefore costs)
BitmapFactory.Options options = null;
options = new BitmapFactory.Options();
options.outHeight = IMAGE_WIDTH_HEIGHT;//give some value
options.outWidth = IMAGE_WIDTH_HEIGHT;//which is suitable for your app image size
BitmapFactory.decodeStream(is, outPadding, options); //try this
Related
I am trying to load bitmaps using an AsyncTask, in order to load them outside UI Thread as it was too slow.
Unfortunatly, I am having issues when starting the app.
The AsyncTask is a class declared inside a "BitmapBank" class, used to handle the different bitmaps of the app. I did it that way to avoid the fact that you can't return something from an Asynctask.
Here is my code :
public Bitmap loadBitmap(Drawable drawable){
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
Canvas canvas = new Canvas(bitmap);
drawable.draw(canvas);
return bitmap;
}
private Bitmap scaleImage(Bitmap bitmap, int ratio){
float widthHeightRatio = (float)(bitmap.getHeight())/(float)(bitmap.getWidth());
int scaleHeight = (int)(widthHeightRatio * AppConstants.SCREEN_WIDTH/ratio);
return Bitmap.createScaledBitmap(bitmap, AppConstants.SCREEN_WIDTH/ratio, scaleHeight, false);
}
private class BitmapTask extends AsyncTask<Drawable, Void, Void> {
public BitmapTask(){
super();
}
#Override
protected Void doInBackground(Drawable... drawables) {
rocket = prepareBitmap(drawables[0]);
astronaut = prepareBitmap(drawables[1]);
bloc = prepareBitmap(drawables[2]);
background = prepareBitmap(drawables[3]);
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
rocket = scaleImage(rocket, 10);
astronaut = scaleImage(astronaut, 20);
bloc = scaleImage(bloc, AppConstants.NB_BLOCS);
background = scaleImage(background, 1);
}
}
And here is the logcat :
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 121701132 byte allocation with 16777216 free bytes and 86MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:975)
at android.graphics.Bitmap.createBitmap(Bitmap.java:946)
at android.graphics.Bitmap.createBitmap(Bitmap.java:913)
at com.example.myapplication.BitmapBank.prepareBitmap(BitmapBank.java:93)
at com.example.myapplication.BitmapBank$BitmapTask.doInBackground(BitmapBank.java:117)
at com.example.myapplication.BitmapBank$BitmapTask.doInBackground(BitmapBank.java:106)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Thanks if you can have a look !
I recommend you use the "Glide" library that automatically handles your problem. Glide is an open source Android library for loading animated images, videos and GIFs. With Glide you can upload and display media from many different sources, such as remote servers or the local file system.
Glide.with(context)
.load(new File(fileUri.getPath())) // Uri of the picture
.into(profileAvatar);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
What is the best way to load a notification image?
Here's my current way: As you can see the image loads synchronously and thus the notification can be delayed. This is a bad way.
public Bitmap getBitmapFromURL(String strURL) {
try {
URL url = new URL(strURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Bitmap bitmap = getBitmapFromURL("https://graph.facebook.com/YOUR_USER_ID/picture?type=large");
// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
builder.setLargeIcon(bitmap);
builder.setContentIntent(pendingIntent);
I really need an answer to continue working on my project.
You should first notify your Notification with no image or place holder, then load your bitmap with an AsyncTask, or use Picasso and Target callback.
Give to your task the builder that you used for the first notify, when bitmap is loaded, add it to the builder, and then re-notify your Notification.
If there's a risk that content had changed before complete image loading, store a variable that identify your current content to show, that you can check before renotify.
You can follow that exemple of MediaNotificationManager provide by google UniversalMusicPlayer project.
In your case :
// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
//builder.setLargeIcon(bitmap); // replace this line with place holder drawable from resources
builder.setContentIntent(pendingIntent);
manager.notify(NOTIFICATION_ID, builder.build());
currentLoadImageTask = new LoadImageTask(manager, builder);
currentLoadImageTask.execute("https://graph.facebook.com/YOUR_USER_ID/picture?type=large");
// ...
static class LoadImageTask extends AsyncTask<String, Void, Bitmap> {
final NotificationManager manager;
final NotificationCompat.Builder builder;
public LoadImageTask(final NotificationManager manager, final NotificationCompat.Builder builder) {
this.manager = manager;
this.builder = builder;
}
#Override
protected Bitmap doInBackground(final String... strings) {
if (strings == null || strings.length == 0) {
return null;
}
try {
final URL url = new URL(strings[0]);
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
final InputStream input = connection.getInputStream();
return BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(final Bitmap bitmap) {
if (bitmap == null || manager == null || builder == null) {
return;
}
builder.setLargeIcon(bitmap);
manager.notify(NOTIFICATION_ID, builder.build());
}
}
With picasso :
// CONSTRUCT THE NOTIFICATION DETAILS
builder.setAutoCancel(true);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Some Title");
builder.setContentText("Some Content Text");
//builder.setLargeIcon(bitmap); // replace this line with place holder drawable from resources
builder.setContentIntent(pendingIntent);
manager.notify(NOTIFICATION_ID, builder.build());
// ...
Picasso.with(context)
.load("https://graph.facebook.com/YOUR_USER_ID/picture?type=large")
.resize(250, 250)
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) {
builder.setLargeIcon(bitmap);
manager.notify(NOTIFICATION_ID, builder.build());
}
#Override
public void onBitmapFailed(final Drawable errorDrawable) {
// Do nothing
}
#Override
public void onPrepareLoad(final Drawable placeHolderDrawable) {
// Do nothing
}
});
If not in UiThread you can create a Runnable and execute it in Looper
final Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(new Runnable() {
#Override
public void run() {
// Call from here
}
});
Picasso is much better simply because using cache.
And I highly recommend you to resize every bitmap you set in notification because it can easily provoc OutOfMemoryException if you dont.
Remember,if you are loading something using the web, you have to wait a bit.
There are several solutions:
Load an image from the web like in your example and show.
Show a stub image and show downloaded image later by updating the notification
Use a little that helps top cache web inches. For instance, picaso
http://square.github.io/picasso/
use Picasso lib to load image from url like
Picasso.with(this.load(imageUri).into(imageview_id);
I am using tessaract to scan text and convert it into a string , so far so good , but i have a problem with grayscaling an image. I have images captured with my camera and I want to grayscale them and to rescale them in order to save some memory , i did this by using the BitmapFactory.Options and the method inSimpleSize(put it in 4).
After that i've tried to get the image from the folder that it is and grayscale it. But didn't work - the text can't be extracted from the photo. However when i removed grayscaling worked.
Here is my code :
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath() , options);
// bitmap = toGrayscale(bitmap);
result = extractText(bitmap);
textView.setText(result);
The extractText method simply calls Tessaract and scan the image and it's working fine without the grayscaling.
My toGrayscale code which i found online ( it is working , i have tried it as a filter and i was happy with it) :
public Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Here is my code for capturing photos with the camera :
if (captureImg != null) {
captureImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCameraActivity();
}
});
private void startCameraActivity() {
try {
String IMGS_PATH = Environment.getExternalStorageDirectory().toString() + "/Noetic/imgs";
prepareDirectory(IMGS_PATH);
String img_path = IMGS_PATH + "/ocr.jpg";
outputFileUri = Uri.fromFile(new File(img_path));
final Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, PHOTO_REQUEST_CODE);
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
I was looking for a solution but didn't find anything. I have some theories why this doesn't work - one of them is because my grayscaling method creates the same image but new (so BitmapFactory.Options.getSampleSize becomes useless). Any help will be much appriciated.
Thanks in advance!
Try to use Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); instead of Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
I want to load a lot of image like instagram do but still get OutOfMemory my code load 18 image at a time and can scroll down to load more.
I also cache image to disk and resize image to fit thumbnail before load to Bitmap
private Bitmap loadBitmap(String id) throws IOException{
String key = id.toLowerCase();
// Check disk cache in background thread
Bitmap image = cacher.get(key);
if (image == null){
// Not found in disk cache
// Process as normal
if(!isCancelled()){
//download image to stream
ByteArrayOutputStream stream = new ByteArrayOutputStream();
DriveApiActivity.getService().files().get(id)
.executeMediaAndDownloadTo(stream);
//decode image to byte array
byte[] byteArray = stream.toByteArray();
stream.close();
//decode byte array to bitmap file
image = decodeToBitmap(
byteArray,
CustomCardView.width,
CustomCardView.height);
// Add final bitmap to caches
cacher.put(key, image);
}
}
return image;
}
the Logcat say exception is come out of cacher.get() method
public Bitmap get(String key) {
synchronized (diskCacheLock) {
// Wait while disk cache is started from background thread
while (diskCacheStarting) {
try {
diskCacheLock.wait();
} catch (InterruptedException e) {
Toast.makeText(
context,
"getBitmapFromCache:" + e.getMessage(),
4).show();
}
}
if (diskLruCache != null) {
Bitmap bitmap = null;
DiskLruCache.Snapshot snapshot = null;
try{
snapshot = diskLruCache.get(key);
if(snapshot == null){
return null;
}
final InputStream in = snapshot.getInputStream(0);
if(in != null){
final BufferedInputStream buffIn =
new BufferedInputStream(in, Utils.IO_BUFFER_SIZE);
bitmap = BitmapFactory.decodeStream(buffIn);
}
}catch(IOException e){
e.printStackTrace();
}finally{
if(snapshot != null){
snapshot.close();
}
}
if(BuildConfig.DEBUG){
Log.d( "cache_test_DISK_", bitmap == null ? "" : "image read from disk " + key);
}
return bitmap;
}
}
return null;
}
this code come from DiskLruCache google provided
You have to use:
largeheap = true
in android. manifest file, from this line you cannot get out of memory error
It will solve your problem
I have an image to the right and a button "download" to the left. the image is from my drawable. now,when i try to click the download i want to put the image to my sdcard downloads. Please help me i only see about download in url. is there other solution for this . Thanks
public class ImageDownloader {
public void download(String url, ImageView imageView) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
task.execute(url);
}
}
/* class BitmapDownloaderTask, see below */
}
First, you need to get your Bitmap. You can already have it as an object Bitmap, or you can try to get it from the ImageView such as:
BitmapDrawable drawable = (BitmapDrawable) ImageView.getDrawable();
Bitmap bitmap = drawable.getBitmap();
Then you must get to directory (a File object) from SD Card such as:
File sdCardDirectory = Environment.getExternalStorageDirectory();
Next, create your specific file for image storage:
File image = new File(sdCardDirectory, "test.png");
After that, you just have to write the Bitmap such as:
boolean success = false;
// Encode the file as a PNG image.
FileOutputStream outStream;
try {
outStream = new FileOutputStream(image);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
/* 100 to keep full quality of the image */
outStream.flush();
outStream.close();
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Finally, just deal with the boolean result if needed. Such as:
if (success) {
Toast.makeText(getApplicationContext(), "Image saved with success",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(),
"Error during image saving", Toast.LENGTH_LONG).show();
}
Don't forget to add the following permission in your Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>