How to retain image quality after uploading it to a server? - android

The code works fine, but the image that is produced looses a good amount of quality. Compression format used is PNG. And also how can I make the image to be saved as .png and not as a .file.
public static void writeBitmapToDisk(String filename, Bitmap paramBitmap,
Context paramContext, Bitmap.CompressFormat paramCompressFormat) {
Log.e("CL", "paramBitmap.getByteCount()" + paramBitmap.getByteCount());
String str = constructFileName(filename);
if (paramBitmap != null) {
try {
FileOutputStream localFileOutputStream = paramContext
.openFileOutput(str, 0);
Log.e("CL", "localFileOutputStream" + localFileOutputStream);
paramBitmap.compress(paramCompressFormat, 100,
localFileOutputStream);
localFileOutputStream.close();
return;
} catch (FileNotFoundException localFileNotFoundException) {
localFileNotFoundException.printStackTrace();
return;
} catch (IOException localIOException) {
localIOException.printStackTrace();
}
}
}

Related

Saved Bitmap to PNG File randomly goes black

I'm processing about 4 images / seconds from camera preview, save it to png File and send it to a server.
I couldn't yet identify why, but 1 time out of 2 the current session will store the .png as full black pictures. the File size is also very small (3kb vs the usual 700kb).
Here's how I store the Bitmap as a PNG file :
public static File SaveImagePNG(Bitmap subimg, String path, String filename) {
FileOutputStream out = null;
File sd = new File(path);
boolean success = true;
if (!sd.exists()) {
success = sd.mkdir();
}
if (success) {
File dest = new File(sd, filename);
try {
out = new FileOutputStream(dest);
if (subimg != null) {
// PNG is a lossless format, the compression factor (100) is ignored
subimg.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
}
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, e.getMessage());
} finally {
try {
if (out != null) {
out.close();
Log.d(TAG, "OK!!");
}
} catch (IOException e) {
Log.d(TAG, e.getMessage() + "Error");
e.printStackTrace();
}
}
return dest;
}
return null;
}
and here's how I call it :
val pathFilePNG = Environment.getExternalStorageDirectory().toString() + "/images"
requestParams[0]?.bitmapRGB?.setHasAlpha(false)
val imageFaceRGBFile = BitmapUtils.SaveImagePNG(requestParams[0]?.bitmapRGB, pathFilePNG, "faceRGB.png")

Bitmap Compression Issues in android

public static void addBitmapToDisk(String filename, Bitmap paramBitmap,
Context paramContext) {
writeBitmapToDisk(filename, paramBitmap, paramContext,
Bitmap.CompressFormat.PNG);
}
public static void writeBitmapToDisk(String filename, Bitmap paramBitmap,
Context paramContext, Bitmap.CompressFormat paramCompressFormat) {
String str = constructFileName(filename);
if (paramBitmap != null) {
try {
FileOutputStream localFileOutputStream = paramContext
.openFileOutput(str, 0);
Log.e("CL", "localFileOutputStream" + localFileOutputStream);
paramBitmap.compress(paramCompressFormat, 100,
localFileOutputStream);
localFileOutputStream.flush();
localFileOutputStream.close();
return;
} catch (FileNotFoundException localFileNotFoundException) {
localFileNotFoundException.printStackTrace();
return;
} catch (IOException localIOException) {
localIOException.printStackTrace();
}
}
}
When I have 2 Mb file it compress up to 100 Kb using above code snippet and image quality is not hd or very clear. so is there any method for quality maintain in android while bitmap compression like instagram

Prevent bitmap being written to disk being scaled

I'm having an issue whereby when I write a bitmap to disk, it gets written to disk, however it gets written as a miniscule image (3kb or less in filesize).
I have checked that the source image is indeed the correct dimensions, however the output image seems shrunk despite configuring the bitmap options to not scale.
#Override
protected Void doInBackground(PPImage... params) {
String filename = "pp_" + position + ".jpg";
File externalStorageDirectory = Environment.getExternalStorageDirectory();
final File destination = new File(externalStorageDirectory, filename);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 16;
opts.inPurgeable = true;
opts.inScaled = false;
decode(opts, Uri.parse(params[0].getUri()), getActivity(), new OnBitmapDecodedListener() {
#Override
public void onDecoded(Bitmap bitmap) {
try {
FileOutputStream out = new FileOutputStream(destination, false);
writeImageToFileTask.this.holder.pathToImage = destination.getAbsolutePath();
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
MediaStore.Images.Media.insertImage(getActivity().getContentResolver(), destination.getAbsolutePath(), destination.getName(), destination.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
});
return null;
}
private void decode(BitmapFactory.Options options, Uri mUri, Context mContext, OnBitmapDecodedListener listener) {
try {
InputStream inputStream;
if (mUri.getScheme().startsWith("http") || mUri.getScheme().startsWith("https")) {
inputStream = new URL(mUri.toString()).openStream();
} else {
inputStream = mContext.getContentResolver().openInputStream(mUri);
}
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
listener.onDecoded(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
How do I ensure that the image being written to file is the same dimensions as the original source image?
You have specified sample size in your code, which will result in resizing:
opts.inSampleSize = 16;
Just remove this line, and the dimension of the output image should be the same.
About the usage of inSampleSize, according to official doc:
For example, inSampleSize == 4 returns an image that is 1/4 the
width/height of the original, and 1/16 the number of pixels. Any value
<= 1 is treated the same as 1.

Android, can't read images I saved to data folder

My app uses the following piece of code to write out images I have resized into the app's data folder:
private void writeImage(Bitmap bmp, String filename)
{
try
{
FileOutputStream stream = openFileOutput(filename, MODE_WORLD_WRITEABLE);
bmp.compress(CompressFormat.PNG, 100, stream);
stream.flush();
stream.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
I am able to read them in a file browser (ddms) and can confirm they appear to have been written.
However, any attempt to load the images results in non-null bitmaps with width and height of -1. I am using the following code to load them:
imageList = getFilesDir().list();
Bitmap bmp = null;
for(String img : imageList)
{
try {
bmp = BitmapFactory.decodeStream(openFileInput(img));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
EDIT: On further inspection, it seems, after conversion the images are of density 160 (and not 240 as they should be) also, after testing a working application it seems the -1 mWidth and -1 mHeight on the bitmaps is irrelevent.
I had same problem.my data folder given smallest image.and cursor return null pointer exception on my getDestination method.then i fixed like it
public void captureNewPhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
targetFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
targetUri = Uri.fromFile(targetFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, targetUri);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
startActivityForResult(intent, 12);
}
And i use like in onActivityResult();
BitmapFactory.Options options = new BitmapFactory.Options();
networkBitmap = BitmapFactory.decodeFile(targetUri.getPath(),
options);
//ImageDialog(networkBitmap);
//String path = getRealPathFromUri(this, Uri.parse(targetUri.getPath()));
String myDeviceModel = android.os.Build.MODEL;
deviceName = Build.MANUFACTURER;
if (myDeviceModel.equals("GT-I9500")) {
} else if (deviceName.contains("samsung")) {
} else {
exif = ReadExif(targetUri.getPath());
if (exif.equals("6")) {
matrixx.postRotate(90);
} else if (exif.equals("7")) {
matrixx.postRotate(-90);
} else if (exif.equals("8")) {
matrixx.postRotate(-90);
} else if (exif.equals("5")) {
matrixx.postRotate(-90);
}
//matrixx.postRotate(-90);
}
networkBitmap = Bitmap.createBitmap(networkBitmap, 0, 0, networkBitmap.getWidth(), networkBitmap.getHeight(), matrixx, true);
Log.e("Taget File ", "Size " + targetFile.length());
if (networkBitmap != null) {
ImageSetting(networkBitmap, System.currentTimeMillis() + filename);
}
public void ImageSetting(Bitmap imageBitmap, final String fileName) {
networkBitmap = imageBitmap;
organizator(networkBitmap, fileName);
networkBitmap = null;
}` public void tamamlandiOndenFoto(Bitmap turnedBitmap, String filename) {
frontFotoFile = storeBitmap(networkBitmap, filename);
ondenFotoPath = ondenFoto.getAbsolutePath();
ondenFotoImageView.setImageBitmap(turnedBitmap);
}`
public File storeBitmap(Bitmap bp, String fileName) {
File sd = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File dest = new File(sd, fileName);
if (bp != null) {
try {
FileOutputStream out = new FileOutputStream(dest);
bp.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("Alinan hata ", " Catch hata ", e);
}
return dest;
} else {
return null;
}
}
I hope give you any idea for your problem.

Managing multiple asynctask to download multiple images from html code, leaking ram, any ideas?

I'm developing an android app. Now I'm parsing bbcode to html and display it inside a textview, the textview is inside a custom listview. I use Html.ImageGetter() to display the images downloaded from AsyncTask.
It works great for a low number of pictures. But if the app is asked to download 40-50 pictures, 40-50 tasks are created and it becomes a mess. Each task opens a stream to download the images. After that it decodes the bytes into bitmaps, resize them, save them to the sdcard and recycles the bitmaps.
Now if the app is loading all this images at the same time it uses a huge amount of ram. I managed to make it pass 48 mb. There is a big gap between 16 and 48 :(. I searched on how to solve this. I downloaded AsyncTask code from google:
http://google.com/codesearch/p?hl=en&sa=N&cd=2&ct=rc#uX1GffpyOZk/core/java/android/os/AsyncTask.java&q=lang:java%20AsyncTask
And set the pool size to 3. But this didn't helped. I really can't figure out where I'm loosing ram. As soon as I put a big task queue my ram goes crazy. After a few images are received it gets worst. I don't think it is the images since I can get to 30 mb before any image is displayed. The app itself including the view, information and its service uses 13 mb, all the rest is leaked here.
Does the queue itself make big ram allocations? Or is the Html.ImageGetter() leaking a huge amount of memory somehow? Is there a better way to do this?
Here I load the images:
public void LoadImages(String source) {
myurl = null;
try {
myurl = new URL(source);
} catch (MalformedURLException e) {
e.printStackTrace();
}
new DownloadImageFromPost().execute(myurl);
}
private class DownloadImageFromPost extends AsyncTask<URL, Integer, Bitmap> {
#Override
protected Bitmap doInBackground(URL... params) {
URL url;
Log.d(TAG, "Starting new image download");
try {
url = params[0];
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length
- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,
length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Bitmap result) {
String name = Environment.getExternalStorageDirectory() + "/tempthumbs/" + myurl.toString().hashCode() +".jpg";
String rname = Environment.getExternalStorageDirectory() + "/tempthumbs/" + myurl.toString().hashCode() +"-t.jpg";
try {
if (result != null) {
hasExternalStoragePublicPicture(name);
ImageManager manager = new ImageManager(context);
Bitmap rezised = manager.resizeBitmap(result, 300, 300);
saveToSDCard(result, name, myurl.toString().hashCode() +".jpg");
saveToSDCard(rezised, rname, myurl.toString().hashCode() +"-t.jpg");
result.recycle();
rezised.recycle();
} else {
}
} catch(NullPointerException e) {
}
Log.d(TAG, "Sending images loaded announcement");
Intent i = new Intent(IMAGE_LOADED);
i.putExtra("image", name);
i.putExtra("source", myurl.toString());
i.putExtra("class", true);
context.sendBroadcast(i);
}
}
private boolean hasExternalStoragePublicPicture(String name) {
File file = new File(name);
if (file != null) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return file.exists();
}
public void saveToSDCard(Bitmap bitmap, String name, String nam) {
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mExternalStorageAvailable = mExternalStorageWriteable = true;
Log.v(TAG, "SD Card is available for read and write "
+ mExternalStorageAvailable + mExternalStorageWriteable);
saveFile(bitmap, name, nam);
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
Log.v(TAG, "SD Card is available for read "
+ mExternalStorageAvailable);
} else {
mExternalStorageAvailable = mExternalStorageWriteable = false;
Log.v(TAG, "Please insert a SD Card to save your Video "
+ mExternalStorageAvailable + mExternalStorageWriteable);
}
}
private void saveFile(Bitmap bitmap, String fullname, String nam) {
ContentValues values = new ContentValues();
File outputFile = new File(fullname);
values.put(MediaStore.MediaColumns.DATA, outputFile.toString());
values.put(MediaStore.MediaColumns.TITLE, nam);
values.put(MediaStore.MediaColumns.DATE_ADDED, System
.currentTimeMillis());
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
Uri uri = context.getContentResolver().insert(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values);;
try {
OutputStream outStream = context.getContentResolver()
.openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
bitmap.recycle();
}
And here i call Html.ImageGetter(), this is inside a list getView:
holder.content.setText(Html.fromHtml(
processor.preparePostText(posts.get(position).post_content),
new Html.ImageGetter() {
#Override public Drawable getDrawable(String source) {
Log.d("Forum Service", "image source: " + source);
if (imageSources.contains(source)) {
for (int x = 0; x < imageSources.size(); x++) {
if (source.equals(imageSources.get(x))) {
String tmp = oImages.get(x);
tmp = tmp.substring(0, tmp.length() - 4);
tmp = tmp + "-t.jpg";
Drawable d = Drawable.createFromPath(tmp);
try {
d.setBounds(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
} catch (NullPointerException e) {
}
Log.d("Forum Service", "Loaded image froms sdcard");
return d;
}
}
} else if (notLoadedImages.contains(source)) {
Log.d("Forum Service", "Waiting for image");
return null;
} else {
notLoadedImages.add(source);
LoadAllIcons loader = new LoadAllIcons(context);
loader.LoadImages(source);
Log.d("Forum Service", "Asked for image");
return null;
}
return null;
}
}, null));
Thanks!
Finally the problem was that all Tasks loaded at the same time. Therefor 40 images where allocated in ram while downloading. I managed to limit the amount of running tasks by doing this modifications on AsyncTask:
private static final int CORE_POOL_SIZE = 2;
private static final int MAXIMUM_POOL_SIZE = 2;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(100);
Mateo there goes your answer http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
And you're done!

Categories

Resources