We are developing an android application for document scanner.
This application is having feature to edit the image like adding magic color, grey mode, Black white,etc. this application has the option to scan "N" number of pages and convert it into PDF at the end.
The flow of the application is First activity is taking photo of the image and the second activity for cropping the image and third activity for editing the image like applying magic color, grey mode and black/white conversion. And in the third activity we have add button,clicking on it will go back to first activty and the same process continues.Once all the images scanned, third activity is haivng done button, clicking on it will create pdf and close the application.
Now the problem is after scanning some 35 pages, it throws out of memory error because we are always keeping original and modified bitmaps as List in the code because its possible for the user to go back to previous images and edit it. At that time i need original version of the image also.
Could you please help me out on the below items.
1) where to keep the bitmaps in this scenario?
2) Is there any way to store the image in the external card and reading it everytime on need basis?
Thanks in advance.
Store the bitmap as cache.
out = new FileOutputStream(filename);
bmp.compress(Bitmap.CompressFormat.PNG, 100, out);
It is prefetable to use cache directory to store such a file rather than storing it persistently. getCacheDir() will return the path to the directory.
Related
In a mobile app one or more images (only jpeg/jpg) - either taken with built-in camera or selected from photo library - are displayed before uploading to a web service.
But loading an image into a FMX TImage / TImageControl / TImageViewer and saving it to stream (or file) makes it smaller, about 45%.
Any idea why this happens and is there a way to avoid the reduction in size ?
As asked for this is the simple test code, nothing special to it:
procedure TImageTest.btnTestClick(Sender: TObject);
var
aFile : string;
begin
if not OpenDialog.Execute then
Exit;
// get jpg file name for loading
aFile := OpenDialog.Filename;
// load into TImage, TImageControl or TImageViewer
ImageViewer.Bitmap.LoadFromFile(aFile);
// and save to file for comparison
ImageViewer.Bitmap.SaveToFile(aFile+'_2.jpg');
end;
The ideal solution to avoid losing image quality is by not relying on the visual controls to store your data. Instead, keep a background object containing the raw image file, and only use the visual controls to display this image to the user. When it comes to saving the image, save it from this background object rather than the visual control.
The same concept applies for about all aspects of programming - visual controls are only meant for visual display to the user, not for storing data.
After an image is selected and the onActivityResult is called, I create a thumbnail to update the original activity view. I also scale the image down and store it in a temporary folder from where it is then picked up by the sync adapter to be uploaded to the server.
To store the scaled-down version of the image I use AsyncTask. The problem is that the file storing routine is slow and can take up to 10 seconds.
File pictureFile = getOutputMediaFile();
FileOutputStream fos = new FileOutputStream(pictureFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close;
While image storing is in process, there is a high chance that users can click to upload the image before the storing routine is done. So, I either have to come up with a way to keep retrying the action until the image file is ready, or make storing routine part of the UI thread which will still make users wait, but this time for the thumbnail to appear.
Has anyone done something similar? Are there patterns for handling similar situations etc?
I have done something like this in one of my application, You can do the saving of the image in a async task and, have an loading spinner (On action bar or anywhere you like) until the file is been saved,
And also by the time async task runs and finished up the saving of the file, You can enable the upload button.
so after a lot of investigation, I finally made my app able to resume state (I simply just modified the OnCreate method in the MainAcitivity.java to load a "restore" page on activity kill if there is a saved bundle instance)
I believe once I fix this final problem, all will be good and I can finally sleep.
HOW do I get the Activity/Intent result from a Camera in PhoneGap once the app has been killed off due to the Background Processes limit or the possibility of "Do not keep activities being checked" (I have a surprising amount of users who have these restrictions enabled)
I thought it might be possible to make the camera save the file in a temp directory and then I just pass the URI through javascript as a hash url (so it'd be something like file:///android_www/index-restore.html#URI_TO_IMAGE)
But my only issue is - How do I even begin this in PhoneGap? I know what to do for everthing bar the temp storage of the image and retrieving the location through onCreate
Ok finally managed it, wrote a hacky solution but it works.
I modified the CordovaInterface and CordovaActivity by adding a function called "getSharedPref" which returns a shared preference that can be accessed throughout the app.
I modified Camera Launcher to force the stored name to be temp.jpg or temp.png depending on what ever input, then store it within the preference.
On the MainActivity.java, I use this.getSharedPref() if a bundle instance is not null, and then check for the key. Unfortunately the only way I could assign the variable in Cordova was by doing
super.loadUrl("javascript: var global_image = '" + file + "'");
then I did the usual routines to add the file in my program and it all work so far! Happy days
Down the track I will probably write a plugin to use, using super.loadUrl("file:///blablabla#" + file); didn't seem to work.
The only issues so far are that Images aren't resized and rotated correctly, and I still need to implement this for the PhotoGallery but so far so good.
edit:
I've managed to get the photos resized and re-orientated :) Next issue is implementing it onto the Photo Gallery now - intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, file); doesn't seem to apply for some reason.
edit:
Latest update - so it turns out AFTER the App has seemingly "crashed", you still get the Intent back regardless, so modifying the source code even more it now auto-calls a global javascript function called "customRestore", which passes over information gathered from the intent and then goes through the normal routine of adding a photo.
I'm stuck with the following scenario and appreciate any help/advice..
Requirement
I have number of categories and subcatergories in my application. Say for example, I have a category "Food" and under which I have subcategories: Mexican, Chinese, Italian etc.. I have around 20 categories and each category has around 30 subcategories.
Each subcategory/category has an Icon associated with it
User would be able to select one or more of these sub-categories, so the UI would be a seectable list view.
Questions:
What's the best way to store and retrieve this data (Strings and Icons), serverside or client side ?
Is there a way to load icons dynamically at runtime, when I show the subcategories? (using http?)
Thanks in advance !
Why would you fetch icon-data from a server? 20 * 30 = 600 icons.
You probably will save hard drive space with respect to the installation. But personally I wouldn't go for that solution.
If you're not in need of a client/server - approach then don't use it. What if the server for example breaks down, or you don't have an internet connection?. The application will then be useless :)
You can load images dynamically as:
BitmapFactory.Options options = new BitmapFactory.Options();
options.outWidth= IMAGE_WIDTH;
options.outHeight= IMAGE_HEIGHT;
Bitmap bm = BitmapFactory.decodeFile("icon image file path", options);
imageView.setImageBitmap(bm);
In your case, you can download all the required icons on mobile's sdcard. So in future,if sub categories increases then you can download new icons for that and can dynamically render on UI.
I guess this question has been asked before, but I can't seem to find a proper answer/solution.
Have a note-taking app, which allows to take pictures. For that I start an intent, that starts up the built-in camera-app. So far so good.
But when I show that image in my app, it's in a much smaller format :(
The funny/weird thing is, that the camera-app did take a full-resolution picture! But for some reason I can't get the full version to show in my app???
So, when I use the standard Android Gallery app, and go to that picture, it is very obvious that it's full size (I can zoom in and see details I really can't see when I zoom in, in my own app). Also, the dimensions are really those of the original picture, taken with the 5MP camera.
In my app, they are very small. My phone has Android 2.2, but the same happens on my emulator (Android 2.1).
How should I retrieve the pictures in my app??? Tried a couple of ways, but none works :( Don't need a complete example (allthough that's very welcome), just a few clues are enough to search for myself.
Tx in advance!!
Greetingz,
Koen<
Very weird, I found the solution/answer by looking at the _ID-values that were being inserted in my own database. First I noticed that when I selected an existing image (via the build-in Android Gallery), I did get the full size image.
When I first took a picture, I got a scaled image. So where was the difference. Apparantly at the location where the _ID of the picture got stored in my database. In my case, and probably most cases, this happens in the onActivityResult procedure.
First take a look at what I initially had:
if(requestCode == REQUEST_CAMERA && resultCode == RESULT_OK){
String timestamp = Long.toString(System.currentTimeMillis());
// get the picture
mPicture = (Bitmap)result.getExtras().get("data");
//save image to gallery
String pictureUrl = MediaStore.Images.Media.insertImage(getContentResolver(), mPicture, getResources().getString(R.string.app_name_short), timestamp);
insertPictureAttachment(mRowId.intValue(), Integer.parseInt(Uri.parse(pictureUrl).getLastPathSegment()));
The "insertPictureAttachment"-method does the actual inserting into the database.
Looking backwards, this was a bit weird anyway ... make a picture, so I could make an URI of it, and then get the last path segment (which is the _ID), so I could insert that into my database.
Eventually, it turns out that I can replace the above code with just one line:
insertPictureAttachment(mRowId.intValue(), Integer.parseInt(result.getData().getLastPathSegment()));
Much shorter, and actually makes more sense ... rather than getting the info from result.getExtras().get("data"), I get my info from result.getData(), which gives the _ID of the original, full-size image.
I will do some further research on this though, cause it's not clear to me yet why I actually don't have to call MediaStore.Images.Media.insertImage(...) ... maybe I will have to if I want specific features (like a custom file location or something like that).
Greetingz,
Koen<