I'm trying to make a simple Android app for my own phone that looks at my Gallery, and for each image/video file:
creates a Bitmap thumbnail of the file
records the file's absolute path on the phone
Essentially, I'll have the following data model:
public class MediaFileModel {
private Bitmap thumbnail;
private String absPath;
// ctor, getters and setters omitted for brevity
}
And I need something that looks at all the files in my Gallery and yields a List<MediaFileModel>. My best attempt is here:
public List<MediaFileModel> getAllGalleryMedia() {
String[] projection = { MediaStore.MediaColumns.DATA };
List<MediaFileModel> galleryMedia = new ArrayList<>();
Cursor cursor = getActivity().getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
null);
// I believe here I'm iterating over all the gallery files (???)
while(cursor.moveToNext()) {
MediaFileModel next = new MediaFileModel();
// is this how I get the abs path of the current file?!?
String absPath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));
Bitmap thumbnail = null;
if (true /* ??? cursor is pointing to a media file that is an image/photo ??? */) {
thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(absPath), 64, 64);
} else {
// else we have a video (I assume???)
thumbnail = ThumbnailUtils.createVideoThumbnail(absPath, MediaStore.Images.Thumbnails.MINI_KIND);
}
next.setThumbnail(thumbnail);
next.setAbsPath(absPath);
galleryMedia.add(next);
}
return galleryMedia;
}
However I'm not sure if my media query is setup correctly and I'm definitely not sure how to determine whether the file is an image/photo of a video, which I (believe I) need so that I can use the correct method for obtaining the thumbnail Bitmap.
Can anyone help nudge me over the finish line here?
Here is a code I was using for something similar, I hope this will help:
//The code has been removed
Note: Sorry I've removed the code because I am not sure if it has some portion copied from other open-sourced codes, I am using it in my apps but I can't remember if it is quoted from other source, so I've removed it, also it could be auto-completed using github copilot
I am storing small images inside a table. The field called "questionImage" is storing these images.
The table looks as follows:
I have two questions:
How can I retrieve the file name of the image files? For example, the first object in the table above has an image named "5D_C.png". How can I get that name using Java in Aandroid? I am using Eclipse, if that makes any difference.
Is there a way to import these images in a batch? For example, if I didn't have any image fields, I could have made an Excel sheet of my data and exported it as CSV into Parse.com. Is the same workflow achievable with image fields inside a class?
First you have to make a Parse query to obtain for the objects you are interested in. See here
Then, in the callback, you can iterate over these elements to collect the file names. Something like this:
public void done(List<ParseObject> objsList, ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " + objsList.size() + " things");
ArrayList<String> fileNames = new ArrayList<>();
for (ParseObject ob : objsList) {
//This is the important part
String fileName = ob.getParseFile("questionImage").getName();
fileNames.add(fileName);
}
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
Similarily, if you want to obtain the files, you can (in the same interation), get the file and save it
byte[] bitmapdata = ob.getParseFile("questionImage").getData();
Bitmap bm = BitmapFactory.decodeByteArray(bitmapdata, 0, bitmapdata.length);
//Save bitmap in a file
Hope this helps.
UPDATE: not sure if I understood correctly your question. With "import" you mean get the images from parse or upload them to parse. Parse is not designed to make massive operations (batch operations are quite limited).
I had two doubts:
1. When i am trying to print The byte array i am getting from java into client side.I am getting strange value kind. I am not sure whether it's a byte array or pixel data.If it's not byte array then what correction needed to do.Code reference are pasted below
2.currently i am reading image from the database and writing into one byte array in server side and i am adding this byte array into json object and sending.But image is not getting displayed Please see the code below:
//this line will fetch the image data from db and i am storing into byte array
byte[] imageData = smpResource.getValue();
//i am adding this byte array into json object and sending.
JSONObject result = new JSONObject();
result.put("image", imageData);
//Client side code looks like:
var temp = null;
var jqxhr = jQuery.post(
'$link.getContextPath()/setEmployee.do',
{
empID: getSelectedEmpID(), empName: getSelectedEmpName()
},
function (data) {
jQuery.each(data, function(field, value){
// here in value i will be getting that byte array and i am storing in the below img src
if( "image" == field ) {
temp = value;
// please check the attachments and please confirm whether it was printing byte array or pixel data
alert("temp" + temp);
}
});
selectedImage.innerHTML = "<img src='data:image/jpg;base64, temp'/>";
,
"json"
).error( function(){
// if there was an error, select the parent...
selectedTreeNode.remove();
});
}
Might be it got little complicated to make you understand guyz but i tried my best.But let me know i will try in some other way.
To show in image with a data/base64 url, you need to encode it in Base64 format (see http://en.wikipedia.org/wiki/Base64). You could modify your backend to write your image into base64 format (see Java BufferedImage to PNG format Base64 String), as a string rather than an array. It's also way more compact for your JSON!
I have an ImageView that is not wanting to display a JPEG, but will display all the other PNG's in the ListView. I have tried things such as adding a transparent background, and nothing works. To get the data, I downloaded all of the images, and stored them into a blob in a SQLite database. I retrieved them by fetching the info from the database, and according to the database, their is binary JPEG data available.
Here is the image I am trying to display (I have it already downloaded in binary data): http://image-store.slidesharecdn.com/1a4f1444-02e2-11e4-9166-22000a901256-large.jpeg
Here is the code I am using to try and convert the binary data back to a Bitmap:
try
{
String profilePictureBytes = submittedImageTemp; // this string holds the binary jpeg, png data, etc.
byte[] encoded;
try
{
encoded = profilePictureBytes.getBytes("ISO-8859-1");
ByteArrayInputStream imageStream = new ByteArrayInputStream(encoded);
Bitmap theBitmap = BitmapFactory.decodeStream(imageStream);
attachPreviewOne.setBackgroundColor(Color.TRANSPARENT);
attachPreviewOne.setImageBitmap(theBitmap);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
A. Extract your jpeg from the blob to a temp file. You might want to use the getCacheDir() folder for that
B. Load it from temp file:
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(jpegTemFile, options); //<------------
imageView.setImageBitmap(bm);
The above should work fine. Still - few things you might want to consider:
C. Depending on your jpeg, the loading operation - decodeFile - might be lengthy. You might want to do it in an
AsyncTask.
D. You might also want to consider setting a sampleSize so to reduce size of loaded image:
options.inSampleSize = 2; // setting to N will reduce in-memory size by factor of N*N
Or, you might use Picasso for the job. I used it in several projects and was happy with what I got:
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)
I am developing an application and testing it on my device running Android 2.2. In my code, I make use of a Bitmap that I retrieve using BitmapFactory.decodeResource, and I am able to make changes by calling bitmap.setPixels() on it. When I test this on a friend's device running Android 1.6, I get an IllegalStateException in the call to bitmap.setPixels. Documentation online says an IllegalStateException is thrown from this method when the bitmap is immutable. The documentation doesn't say anything about decodeResource returning an immutable bitmap, but clearly that must be the case.
Is there a different call I can make to get a mutable bitmap reliably from an application resource without needing a second Bitmap object (I could create a mutable one the same size and draw into a Canvas wrapping it, but that would require two bitmaps of equal size using up twice as much memory as I had intended)?
You can convert your immutable bitmap to a mutable bitmap.
I found an acceptable solution that uses only the memory of one bitmap.
A source bitmap is raw saved (RandomAccessFile) on disk (no ram memory), then source bitmap is released, (now, there's no bitmap at memory), and after that, the file info is loaded to another bitmap. This way is possible to make a bitmap copy having just one bitmap stored in ram memory per time.
See the full solution and implementation here: Android: convert Immutable Bitmap into Mutable
I add a improvement to this solution, that now works with any type of Bitmaps (ARGB_8888, RGB_565, etc), and deletes the temp file. See my method:
/**
* Converts a immutable bitmap to a mutable bitmap. This operation doesn't allocates
* more memory that there is already allocated.
*
* #param imgIn - Source image. It will be released, and should not be used more
* #return a copy of imgIn, but muttable.
*/
public static Bitmap convertToMutable(Bitmap imgIn) {
try {
//this is the file going to use temporally to save the bytes.
// This file will not be a image, it will store the raw image data.
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "temp.tmp");
//Open an RandomAccessFile
//Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
//into AndroidManifest.xml file
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
// get the width and height of the source bitmap.
int width = imgIn.getWidth();
int height = imgIn.getHeight();
Config type = imgIn.getConfig();
//Copy the byte to the file
//Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888;
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()*height);
imgIn.copyPixelsToBuffer(map);
//recycle the source bitmap, this will be no longer used.
imgIn.recycle();
System.gc();// try to force the bytes from the imgIn to be released
//Create a new bitmap to load the bitmap again. Probably the memory will be available.
imgIn = Bitmap.createBitmap(width, height, type);
map.position(0);
//load it back from temporary
imgIn.copyPixelsFromBuffer(map);
//close the temporary file and channel , then delete that also
channel.close();
randomAccessFile.close();
// delete the temp file
file.delete();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return imgIn;
}
Copy the bitmap to itself with mutable option true. This way neither extra memory consumption nor long lines of code are needed.
Bitmap bitmap= BitmapFactory.decodeResource(....);
bitmap= bitmap.copy(Bitmap.Config.ARGB_8888, true);
We can first set options for BitmapFactory by instantiating an BitmapFactory.Options class and then set the options field named 'inMutable' as true and and then pass this options instance to decodeResource.
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inMutable = true;
Bitmap bp = BitmapFactory.decodeResource(getResources(), R.raw.white, opt);
Here's a solution i've created that uses the internal storage and doesn't require any new permission, based on "Derzu"'s idea, and the fact that starting with honeycomb, this is built in :
/**decodes a bitmap from a resource id. returns a mutable bitmap no matter what is the API level.<br/>
might use the internal storage in some cases, creating temporary file that will be deleted as soon as it isn't finished*/
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static Bitmap decodeMutableBitmapFromResourceId(final Context context, final int bitmapResId) {
final Options bitmapOptions = new Options();
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB)
bitmapOptions.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), bitmapResId, bitmapOptions);
if (!bitmap.isMutable())
bitmap = convertToMutable(context, bitmap);
return bitmap;
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static Bitmap convertToMutable(final Context context, final Bitmap imgIn) {
final int width = imgIn.getWidth(), height = imgIn.getHeight();
final Config type = imgIn.getConfig();
File outputFile = null;
final File outputDir = context.getCacheDir();
try {
outputFile = File.createTempFile(Long.toString(System.currentTimeMillis()), null, outputDir);
outputFile.deleteOnExit();
final RandomAccessFile randomAccessFile = new RandomAccessFile(outputFile, "rw");
final FileChannel channel = randomAccessFile.getChannel();
final MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes() * height);
imgIn.copyPixelsToBuffer(map);
imgIn.recycle();
final Bitmap result = Bitmap.createBitmap(width, height, type);
map.position(0);
result.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
outputFile.delete();
return result;
} catch (final Exception e) {
} finally {
if (outputFile != null)
outputFile.delete();
}
return null;
}
another alternative is to use JNI in order to put the data into it, recycle the original bitmap, and use the JNI data to create a new bitmap, which will be (automatically) mutable, so together with my JNI solution for bitmaps, one can do the following:
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
final JniBitmapHolder bitmapHolder=new JniBitmapHolder(bitmap);
bitmap.recycle();
bitmap=bitmapHolder.getBitmapAndFree();
Log.d("DEBUG",""+bitmap.isMutable()); //will return true
however, i'm not sure what is the minimal requirement of API level. it works very well on API 8 and above.
I know I'm late to the party, but this is how we avoided this painfully annoying Android problem, and cropped and modified an image with only one copy ever in memory.
Situation
we want to process the pixels of a cropped version of an image saved to file. With high memory demands, we never want to have more than one copy of this image in memory at any given time.
What should have worked but didn't
Opening the image subsection (the bit we wanted to crop to) with BitmapRegionDecoder, passing in a BitmapFactory.option with inMutable = true, processing the pixels then saving to file.
Though our app declared an API minimum of 14 and a target of 19, BitmapRegionDecoder was returning an immutable bitmap, effectively ignoring our BitMapFactory.options
What won't work
opening an mutable image with BitmapFactory (which respects our inMutable option) and croppping it: all cropping techniques are non-imperitive (require a copy of the entire image to exist in memory at a time, even if garbage collected immediately after with overwrites and recycling)
opening an immutable image with BitmapRegionDecoder (effectively cropped) and converting it to a mutable one; all available techniques again require a copy in memory.
The great work-around of 2014
open the full size image with BitmapFactory as a mutable bitmap, and perform our pixel operations
save the bitmap to file and recycle it from memory (it's still un-cropped)
open the saved bitmap with BitmapRegionDecoder, opening only the region to be cropped to (now we don't care if the bitmap is immutable or not)
save this bitmap (which has effectively been cropped) to file, overwriting the previously saved bitmap (which was un-cropped)
With this method, we can crop and perform pixel processing on a bitmap with only 1 copy ever in memory (so we can avoid those pesky OOM errors as much as possible), trading RAM for time as we have to perform extra (slow) file IOs.
It is happening because you want to resize the bitmap by calling setHeight() or setWidth()
To resize any bitmap or drawable (Png, Svg, vector, etc)
public Bitmap editMyBitmap(int drawableId, int newHeight, int newWidth) {
Bitmap myBitmap = BitmapFactory.decodeResource(getResources(), drawableId);
myBitmap = Bitmap.createScaledBitmap(myBitmap, newWidth, newHeight, false);
return myBitmap;
}
Usage Example:
Bitmap facebookIcon = editMyBitmap(R.drawable.facebookImage);
// now use it anywhere
imageView.setBitmapImage(facebookIcon);
canvas.drawBitmap(facebookIcon, 0, 0, null);
I know the question is solved but what about:
BitmapFactory.decodeStream(getResources().openRawResource(getResources().getIdentifier("bitmapname", "drawable", context.getPackageName())))