How to store thumbnails for easy retrieval - android

I'm currently creating thumbnails by using the ThumbnailUtils.createVideoThumbnail() method; which returns a bitmap. However, I want to store that thumbnail in a database so I can access it later and I don't have to keep recreating the thumbnails. My questions is how should I store this thumbnail in the database? Do thumbnails have filepaths? Or should I create the thumbnails and just retrieve them using the Mediastore every time I need to use it? If so how would I go about saving/storing the thumbnail so I can use the Mediastore to query it?
Thanks for your help.

If you're getting a Thumbnail object from video, you need to save it in either storage or database.
To save in database :
Bitmap thumbnailBitmap; // Get it with your approach
SQLiteDatabase writableDb; // Get it with your approach
if (thumbnailBitmap != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
thumbnailBitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] thumbnailBitmapBytes = stream.toByteArray();
ContentValues values = new ContentValues();
values.put("IMAGEID", "your_image_id");
values.put("BYTES", thumbnailBitmapBytes);
writableDb.insert("TABLE_NAME", null, values);
}
To get it back from database :
public static synchronized Bitmap getImage(String imageID, Context context) {
SQLiteDatabase writableDb; // Get it with your approach
Bitmap bitmap = null;
Cursor cs = null;
try {
String sql = "SELECT BYTES FROM TABLE_NAME WHERE IMAGEID = ?;";
cs = writableDb.rawQuery(sql, new String[]{imageID});
if (cs != null && cs.moveToFirst()) {
do {
byte[] bytes = cs.getBlob(0);
if (bytes != null) {
try {
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
} catch (Exception e) {
Log.e("TAG", "Exception", e);
}
} else {
Log.e("TAG", "IMAGE NOT FOUND");
}
} while (cs.moveToNext());
}
} catch (Exception e) {
Log.e("TAG", "Exception", e);
} finally {
if (cs != null) {
cs.close();
}
}
return bitmap;
}
The database structure:
String imageTable = "CREATE TABLE TABLE_NAME("
+ "IMAGEID TEXT PRIMARY KEY, "
+ "BYTES BLOB)";

Related

Cannot read image written to file

I am trying to write an image on storage then reading it. Write operation is successful but read fails. I have tried using intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); when calling the responsible activity but was of no help.
This is how I write image:
public void savepic(Bitmap pic)
{
SQLiteDatabase db = dBcontract.getWritableDatabase();
ContentValues values = new ContentValues();
FileOutputStream out = null;
try
{
File image = createImageFile();
Uri photoURI = FileProvider.getUriForFile(context, "lcukerd.com.android.fileprovider", image);
out = new FileOutputStream(image);
pic.compress(Bitmap.CompressFormat.PNG, 100, out);
values.put(eventDBcontract.ListofItem.columnpic, photoURI.toString());
db.insert(eventDBcontract.ListofItem.tableName2, null, values);
Log.i(TAG, "Pic saved " + photoURI.toString());
} catch (Exception e)
{
e.printStackTrace();
} finally
{
try
{
if (out != null)
{
out.close();
}
} catch (IOException e)
{
e.printStackTrace();
}
}
}
private File createImageFile() throws IOException
{
String EName = "Image";
File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(EName, ".jpg", storageDir);
return image;
}
This is how I read image:
public Bitmap getDownloadedpics(int index)
{
SQLiteDatabase db = dBcontract.getReadableDatabase();
Cursor cursor = db.query(eventDBcontract.ListofItem.tableName2, projection2, null, null, null, null, null);
cursor.moveToPosition(index);
Bitmap photo = null;
try
{
Log.d(TAG,cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic)));
photo = MediaStore.Images.Media.getBitmap(context.getContentResolver(),
Uri.parse(cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic))));
} catch (IOException e)
{
Log.e(TAG, "Can't read image");
}
Log.d(TAG, "Returned " + String.valueOf(cursor.getCount()) + " pics");
return (photo);
}
I get Exception at `photo =
MediaStore.Images.Media.getBitmap(context.getContentResolver(),
Uri.parse(cursor.getString(cursor.getColumnIndex(eventDBcontract.ListofItem.columnpic))));
Exception is :
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{6118b35 21772:lcukerd.com.instaswipe/u0a157} (pid=21772, uid=10157) that is not exported from uid 10101
I have checked other similar question but seems like they are all for some other type of problem. Help me solve it.
Instead of photoUri.toString() put image.getAbsolutePath() in your database.
If you want to read the file get the path from the database. Construct a File object en use FileInputStream. Then let BitmapFactory read the data from the stream.

Getting path from Uri from Google Photos app

I have an app which allows to select photos with an external app. Then I take the path of the photo from the uri and use it for internal actions.
When user selects a photo with Google Photo, if the picture is locally stored then the next code works perfectly. But if the picture is in the cloud the result of cursor.getString(index) is null.
I've search for some info, but not sure about the solution
final String[] projection = { "_data" };
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow("_data");
return cursor.getString(index);
}
Thank you!
Finally and according to #CommonsWare answer and the previous post about this issue I solved getting the InputStream from the uri, coping into a new temporal file and passing the path to the function I need to use.
Here is the simplified code:
public String getImagePathFromInputStreamUri(Uri uri) {
InputStream inputStream = null;
String filePath = null;
if (uri.getAuthority() != null) {
try {
inputStream = getContentResolver().openInputStream(uri); // context needed
File photoFile = createTemporalFileFrom(inputStream);
filePath = photoFile.getPath();
} catch (FileNotFoundException e) {
// log
} catch (IOException e) {
// log
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return filePath;
}
private File createTemporalFileFrom(InputStream inputStream) throws IOException {
File targetFile = null;
if (inputStream != null) {
int read;
byte[] buffer = new byte[8 * 1024];
targetFile = createTemporalFile();
OutputStream outputStream = new FileOutputStream(targetFile);
while ((read = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, read);
}
outputStream.flush();
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return targetFile;
}
private File createTemporalFile() {
return new File(getExternalCacheDir(), "tempFile.jpg"); // context needed
}
When user selects a photo with Google Photo, if the picture is locally stored then the next code works perfectly.
Not necessarily. There is no requirement for that Uri to respond with a _data column to a query(). There is no requirement for the value it returns to be useful to you (e.g., a file on internal storage or removable storage that you cannot access).
If you need the photo loaded into an ImageView, pass the Uri to an image-loading library, such as Picasso.
If you need the bytes of the photo, use openInputStream() with ContentResolver to get an InputStream on the content identified by the Uri. Please open and read from the InputStream on a background thread.

Index 1 requested with size of 3

I created a simple app in which the image store from the ImageView to the database.
But when click on the retrive button is show that index 1 requested with size of 3.
I don't know what thing is going wrong.
database class:
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_IMAGE_TABLE = "CREATE TABLE " +TABLE_NAME + "("
+ IMAGE_KEY + " BLOB )";
db.execSQL(CREATE_IMAGE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase db, int i, int i1) {
db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME);
onCreate(db);
}
public boolean insertData(byte[]image )throws SQLiteException
{
SQLiteDatabase db = this.getWritableDatabase();
ContentValues cv=new ContentValues();
cv.put(IMAGE_KEY,image);
long result= db.insert(TABLE_NAME,null,cv);
if(result==-1)
return false;
else
return true;
}
public Cursor getAllData()
{
SQLiteDatabase db=this.getReadableDatabase();
Cursor res=db.rawQuery("select * from "+TABLE_NAME,null);
byte[]img=res.getBlob(0);
return res;
}
And this is the activity class:
public void button2(View view)
{
try {
Cursor res = myDb.getAllData();
if (res ==null) {
showMessage("error", "no data found");
} else {
StringBuffer buffer = new StringBuffer();
while (res.moveToNext()) {
buffer.append("id:" + res.getBlob(0) + "\n");
byte[] image = res.getBlob(0);
Bitmap bmp = BitmapFactory.decodeByteArray(image, 0,
image.length);
imagee.setImageBitmap(bmp);
}
// showMessage("DATA", buffer.toString());
}
}
catch (Exception e)
{
Toast.makeText(getBaseContext(),e.getMessage(),
Toast.LENGTH_LONG).show();
}}
public void buttonn(View view)
{
Bitmap bitmap = ((BitmapDrawable) imagee.getDrawable()).getBitmap();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 0, outputStream);
byte[] data = outputStream.toByteArray();
boolean isInserted = myDb.insertData(data);
if (isInserted == true)
Toast.makeText(getBaseContext(), "Registration Succes!",
Toast.LENGTH_SHORT).show();
else
Toast.makeText(getBaseContext(), "No Record Registered!",
Toast.LENGTH_SHORT).show();
}
}
I tried most but couldn't do not thing.I change it from res.movetoNext but show the same error and use res.movetoFirst it also show the same error
Android sqlite CursorWindow has a fixed size buffer that is 2MB on most configurations. You cannot move around rows any larger than that.
Don't store large binary data such as images in Android sqlite. Use external storage instead and just save the path in your database.
Check this code about how to save an image in android:
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath=new File(directory,"profile.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (Exception e) {
e.printStackTrace();
} finally {
fos.close();
}
return directory.getAbsolutePath();
}
You need just to add the path of your image into your database instead of the blob image.
Reference: Saving and Reading Bitmaps/Images from Internal memory in Android

Inserting Sent MMS into sent box

I'm trying to insert a MMS into the sent database but alas I haven't been able to view it in the native android application.
my insertion code:
ContentValues values = new ContentValues();
values.put("thread_id", thread_id);
values.put("date", time);
values.put("read", true); //read status
values.put("sub", text); //mms subject
values.put("msg_box", 2); //message box. in this case outbox
Uri mmsUri = context.getContentResolver().
insert(Uri.parse("content://mms"), values);
Log.v("MMSProjectActivity", "Message saved at: " + mmsUri);
ContentValues mmsPartValue = new ContentValues();
mmsPartValue.put("ct", "image/jpeg"); //mime; for example image/jpeg
Uri picUri = picUris.get(0);
String [] fileNameSplit = picUri.toString().split("/");
String fileName = fileNameSplit[fileNameSplit.length-1] + ".jpg";
String messageId = mmsUri.getLastPathSegment().trim(); //id of MMS at content://mms
Uri partUri = Uri.parse("content://mms/" + messageId + "/part");
Uri mmsPartUri = context.getContentResolver().insert(partUri, mmsPartValue);
OutputStream os;
InputStream is;
try
{
os = context.getContentResolver().openOutputStream(mmsPartUri);
is = context.getContentResolver().openInputStream(picUris.get(0));
byte[] buffer = new byte[256];
for (int len = 0; (len = is.read(buffer)) != -1; ) {
os.write(buffer, 0, len);
}
} catch (FileNotFoundException e)
{
Log.v("MMSProjectActivity", "MMS not saved FileNotFoundException");
e.printStackTrace();
} catch (IOException e)
{
Log.v("MMSProjectActivity", "MMS not saved IOException");
e.printStackTrace();
}
Log.v("MMSProjectActivity", "MMS part value saved at: " + mmsPartUri);
anybody have any idea what am I doing wrong?
I think what you need is in this class of the source code .
Generally take a look at how they do it at google..
specifically take a look at this method
private static Uri createDraftMmsMessage(PduPersister persister, SendReq sendReq,
SlideshowModel slideshow) {
try {
PduBody pb = slideshow.toPduBody();
sendReq.setBody(pb);
Uri res = persister.persist(sendReq, Mms.Draft.CONTENT_URI);
slideshow.sync(pb);
return res;
} catch (MmsException e) {
return null;
}
}
And after creating the Draft (step one) then you update the draft to sent. by calling the other method
private static void updateDraftMmsMessage(Uri uri, PduPersister persister,
SlideshowModel slideshow, SendReq sendReq) {
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
LogTag.debug("updateDraftMmsMessage uri=%s", uri);
}
if (uri == null) {
Log.e(TAG, "updateDraftMmsMessage null uri");
return;
}
persister.updateHeaders(uri, sendReq);
final PduBody pb = slideshow.toPduBody();
try {
persister.updateParts(uri, pb);
} catch (MmsException e) {
Log.e(TAG, "updateDraftMmsMessage: cannot update message " + uri);
}
slideshow.sync(pb);
}
Now I know you cannot run this code from your app since you're not building in the source, or even if you are it may be a challenge to do so (even though I think that if you do build in the source if you code correctly the google code should handle the save stuff)
in any case you should be able to save mms message in the provider by following what they do in this class.
cheers...
and post your progress...

How can I update the album art path using contentResolver?

I want to update/insert a new image for an album in MediaStore but i can't get it work..
This is my code:
public void updateAlbumImage(String path, int albumID) {
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Albums.ALBUM_ART, path);
int n = contentResolver.update(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, values, MediaStore.Audio.Albums.ALBUM_ID + "=" + albumID, null);
Log.e(TAG, "updateAlbumImage(" + path + ", " + albumID + "): " + n);
}
The error is:
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): java.lang.UnsupportedOperationException: Unknown or unsupported URL: content://media/external/audio/albums
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:131)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:111)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at android.content.ContentProviderProxy.update(ContentProviderNative.java:405)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at android.content.ContentResolver.update(ContentResolver.java:554)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at com.liviu.app.smpp.managers.AudioManager.updateAlbumImage(AudioManager.java:563)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at com.liviu.app.smpp.ShowAlbumsActivity.saveImageFile(ShowAlbumsActivity.java:375)
03-24 03:09:46.323: ERROR/AndroidRuntime(5319): at com.liviu.app.smpp.ShowAlbumsActivity.onClick(ShowAlbumsActivity.java:350)
Thank you!
See this post:
Android set Album Thumbnail
The bit you need is here:
ContentResolver res = context.getContentResolver();
Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
if (uri != null) {
InputStream in = null;
try {
in = res.openInputStream(uri);
return BitmapFactory.decodeStream(in, null, sBitmapOptions);
} catch (FileNotFoundException ex) {
// The album art thumbnail does not actually exist. Maybe the user deleted it, or
// maybe it never existed to begin with.
Bitmap bm = getArtworkFromFile(context, null, album_id);
if (bm != null) {
// Put the newly found artwork in the database.
// Note that this shouldn't be done for the "unknown" album,
// but if this method is called correctly, that won't happen.
// first write it somewhere
String file = Environment.getExternalStorageDirectory()
+ "/albumthumbs/" + String.valueOf(System.currentTimeMillis());
if (ensureFileExists(file)) {
try {
OutputStream outstream = new FileOutputStream(file);
if (bm.getConfig() == null) {
bm = bm.copy(Bitmap.Config.RGB_565, false);
if (bm == null) {
return getDefaultArtwork(context);
}
}
boolean success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream);
outstream.close();
if (success) {
ContentValues values = new ContentValues();
values.put("album_id", album_id);
values.put("_data", file);
Uri newuri = res.insert(sArtworkUri, values);
if (newuri == null) {
// Failed to insert in to the database. The most likely
// cause of this is that the item already existed in the
// database, and the most likely cause of that is that
// the album was scanned before, but the user deleted the
// album art from the sd card.
// We can ignore that case here, since the media provider
// will regenerate the album art for those entries when
// it detects this.
success = false;
}
}
if (!success) {
File f = new File(file);
f.delete();
}
} catch (FileNotFoundException e) {
Log.e(TAG, "error creating file", e);
} catch (IOException e) {
Log.e(TAG, "error creating file", e);
}
}
} else {
bm = getDefaultArtwork(context);
}
return bm;
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) {
}
}
}

Categories

Resources