I have pictures to send to a server from an android device.
I'm trying to find out which is perhaps better as a storage option.
I'm struggling to see which format will use less storage space on the device and server. I am already sending data(text) from Db's over to server.
So wondering if it's best to put the pictures as byte arrays into db (stored and sent) seeing as I have Db's already
OR
Keep the pic's out of db and send separate.
i hope this helps you
public byte[] extractBytes (String ImageName) throws IOException {
File imgPath = new File(ImageName);
BufferedImage bufferedImage = ImageIO.read(imgPath);
WritableRaster raster = bufferedImage .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return ( data.getData() );
}
Related
I'm pretty new to programming Android and I have a problem - I'm creating an app which stores "funny" images and enables user to view all of them, rate them (at least I want to make it so ;) ). I was trying to make a very simple database which stores images as BLOBs but someone on forum told me that this is a bad idea - so I decided to store images on SD like (this code is mainly from Stack although):
private void savePicToSD(){
Toast.makeText(getActivity(),"Saving...",Toast.LENGTH_SHORT).show();
//getting BitMap from ImageView
Bitmap imageToSave=((BitmapDrawable)preview.getDrawable()).getBitmap();
// getting env var representing path
String root= Environment.getExternalStorageDirectory().toString();
Toast.makeText(getActivity(),root,Toast.LENGTH_LONG).show();
File dir=new File(root+DIR_NAME_);
dir.mkdirs();
String fileNam="Image-"+FILE_COUNTER_+".jpg";
FILE_COUNTER_=FILE_COUNTER_.add(BigInteger.valueOf(1));
File fileSav=new File(dir,fileNam);
//I don't use try-with-resources because of API lvl
FileOutputStream out=null;
try{
out=new FileOutputStream(fileSav);
//saving compressed file ot the dir
imageToSave.compress(Bitmap.CompressFormat.JPEG,90,out);
out.flush();
out.close();
}catch(Exception ex) {
ex.printStackTrace();
Toast.makeText(getActivity(), "Error during saving.", Toast.LENGTH_SHORT).show();
}
Toast.makeText(getActivity(),"Image saved.",Toast.LENGTH_LONG).show();
}
after making it I now don't know how to store this "reference" and how to implement "fetching data from DB" - I was thinking about storing (with some sort of other data releated to specific photo) in DB string contatining path to the image and later while reading data from DB, read also the image - but how to do this efficiently? (I know that fetching data from DB has to be done as a Thread (AsyncTask ? ))?
I think the best you can do is storing the path of the image in BDD or a relative path and then access it
Store imagePath/fileName in your local database along with saving the image in the file system(SD card), and then when you want to get back that image just fetch that image from the file system by using imagePath/fileName stored in database.
I hope that you know how to create file and store in SD card.
I wrote an android application that part of it is to handle upload and download documents. Currently I am using the Microsoft Azure server to save the files on.
The way I am currently doing it is by turning the files to a string and saving it that way on the Azure server:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileInputStream fis;
try {
fis = new FileInputStream(new File(Uridata.getPath()));
byte[] buf = new byte[1024];
int n;
while (-1 != (n = fis.read(buf)))
baos.write(buf, 0, n);
} catch (Exception e) {
e.printStackTrace();
}
byte[] bbytes = baos.toByteArray();
item.setStringFile(Base64.encodeToString(bbytes, Base64.URL_SAFE));
item.setName(Uridata.getLastPathSegment());
where item is my class that saves the string representation and the name of the file and is being loaded to the Azure, Uridata is an Uri instance of the file chosen.
I have one main problem with this solution and it is the limit on the file size.
I am searching for a good server to use instead of the Azure (maybe a RESET one) and if there is a better way to save files of all kinds (pdf, word...).
I will also want in the future to use the same data in a web interface
Does anybody have any suggestions on how to do it?
Thanks in advance!
To start, you don't have to transform the file into a string, you can just save it as a file. You have the possibility of losing data by continuing to do that. See: How do I save a stream to a file in C#?
If you're looking for another service to save files, then you should look into Azure Blob Storage. It will allow you to upload as much data as you want to a storage service for arbitrary files. See for example:
https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/
i want to save picture in sqlite DB and then open that in java android!
in order to save picture i write a C++ program with Qt.
in C++ code i open picture as file, then convert it to QByteArray.
QFile file(foodImagePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
ShowError("Bad Image File.");
return;
}
QByteArray imageData = file.readAll();
but when i retrieve picture with sqliteManager the output is a bad file.(not correct picture )
then i decide to save picture as a Text in sqlite and convert it to base64 in C++ side!
QString(imageData.toBase64())
and in android side retrieve whit this code.
String imgString = cur.getString(0);
if( imgString != null)
{
byte[] imgByte = Base64.decode(imgString, Base64.DEFAULT);
pic = BitmapFactory.decodeByteArray(imgByte,0,imgByte.length);
}
and now the i can see the picture , but it was a little damaged!
can any body help me? PLZ.
An image file is not a text file.
Drop the QIODevice::Text flag.
(Using Base64 is not necessary if you handle the blobs correctly.)
The final objective will be clear shortly.
I want to create a file object and instead of getting data from a real physical file I want to provide the buffer myself.
Then, I want to use this file, which does not really exist in the sdcard or anywhere outside my app, give it a name and send it by email as an attachment (using the EXTRA_STREAM).
I found the following bit of code, by Adriaan Koster (#adriaankoster), the post Write byte[] to File in Java
// convert byte[] to File
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
File fileFromBytes = (File) ois.readObject();
bis.close();
ois.close();
System.out.println(fileFromBytes);
I used it to create this function
private File fileFromBytes(byte[] buf) {
File f = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bis);
f = (File) ois.readObject();
bis.close();
ois.close();
}
catch (Exception e) {}
return f;
}
and here is where I am stuck, because when I use it:
// When sent as body the mail is sent OK
// emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, dump());
// When I try to attach the mail is empty
emailIntent.putExtra(android.content.Intent.EXTRA_STREAM, fileFromBytes(dump().getBytes()));
I know from examples I've seen the second argument should be an URI, but: How do I create a virtual URI to fit my file?
EDIT:
The option to attach data directly from within the application is important to certain kind of applications. Namely, security & banking applications that do not want to move sensitive data around too much. Surely if the data does not reach the sdcard and goes directly to a mail attachment it is harder to sniff than within the application memory.
This is not my specific case, but I wanted to point out that this capability is important to have.
The first thing you'll want to do, I imagine, is create a ContentProvider. You can see an example implementation here
https://github.com/dskinner/AndroidWeb/blob/master/src/org/tsg/web/WebContentProvider.java
where in the above link's case, you would add this to your AndroidManifest.xml
<provider
android:name="org.tsg.web.WebContentProvider"
android:authorities="your.package.name" />
Now, you'll have a content uri available for use, content://your.package.name/.
The portion of the above ContentProvider your interested in, again I imagine, is the openFile method. When sharing data by intent across apps, certain things are expected. In your case, you're looking to share some byte data that's meant to be attached to the email.
So if you pass in a content uri to the email app such as content://your.package.name/foo with the appropriate intent flags, then openFile will get called on your ContentProvider. In this case, you can inspect the end of the uri segment to see foo was requested, and return appropriately.
The next issue you bring up is not having the file actually on disk. While I can't vouch for the method you used above (though it looks kosher), what you need to be returning is a ParcelFileDescriptor from your ContentProvider. If you look at the link I provided, you could possibly try to use that as a sample to get the file descriptor from your File object (my knowledge waivers here), but I imagine, the data simply wont be available at that point.
What you do bring up is security though. It's important to note that you can write data to disk privately so only the app has access to the data. I believe, but you might want to double check on this, if that data is private to the app, you can expose it via the ContentProvider and possibly lock down who and how the provider gets used, who can call it, etc. You may want to dig into android docs for that portion or look at some other SO questions.
Anyway, good luck.
Create the file in the application's cache directory. It will be created in the internal filesystem. Use 'getCacheDir()' API for getting the path to the cache dir. Write the data into this dir and then get the URI from the File object using ' Uri.fromFile (File file) '. When you are finished with the file, delete it.
Your application's cache is only available to your app, hence its safe to use for your purpose.
You can do some encryption if the data is too critical.
I think in order to do this, you are going to have to expose a ContentProvider, which will allow you handle a URI. The email application should then openInputStream on your URI, at which point you return an InputStream on your in-memory data.
I've not tried it, but in theory this should work.
i was busy with adding attachment to mail and i can send mail with attachment.
if you want to take a look: can not send mail with attachment in Android
My application allows users to take a photo using the camera and save it as their profile picture. There can be only 1 image stored at a time?
Is it a bad idea to use SharedPrefertences for this purpose although I am only storing 1 image? (Converting image to Base64). What are the cons?
If storing the image using shared preferences is not a good idea, what are the alternatives?
I think storing binary data in SharedPreferences is not a good idea. Instead save it to the filesystem. Example for that, if the data is coming from an InputStream:
storeImage( new File(context.getFilesDir().getAbsolutePath() + fileDir),
is,
"profile.png" );
public static void storeImage(
File fileDir,
InputStream inputStream,
String fileName ) throws IOException {
File file = new File( fileDir,fileName );
FileOutputStream fos = new FileOutputStream( file );
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
inputStream.close();
fos.close();
bitmap.recycle();
bitmap = null;
}
Where context can be the Application/Activity context.
There is no reason why you can't use SharedPreferences to store a single image as a Base64 String, Of course this isn't really a scalable approach as when the SharedPreferences are loaded, every image would be loaded into memory at once, but that's not what your looking for.
The other possible approaches you can take is to store the images either using the internal or external storage APIs or to store them in a database
In general for this kind of thing you should be looking to use something other than shared preferences, however in this case, I can't see there been an actual issue to the approach your suggesting.