I am trying to convert a google doc into a bitmap so I can perform OCR within it.
I am however getting the errors:
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /document/acc=4;doc=14882: open failed: ENOENT (No such file or directory)
E/ReadFile: Bitmap must be non-null
E/CropTest: Failed to read bitmap
Code:
/**
* Fires an intent to spin up the "file chooser" UI and select an image.
*/
public void performFileSearch(View view) {
// ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file
// browser.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// Filter to only show results that can be "opened", such as a
// file (as opposed to a list of contacts or timezones)
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Filter to show only images, using the image MIME data type.
// If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
// To search for all documents available via installed storage providers,
// it would be "*/*".
intent.setType("application/vnd.google-apps.document");
startActivityForResult(intent, READ_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData){
if(requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK){
Uri uri = null;
if(resultData != null){
uri = resultData.getData();
Log.i(TAG, "Uri" + uri.toString());
Toast.makeText(MainActivity.this, "Uri:" + uri.toString(), Toast.LENGTH_LONG).show();
IMGS_PATH = Environment.getExternalStorageDirectory().toString()+ "/TesseractSample/imgs";
prepareDirectory(IMGS_PATH);
prepareTesseract();
startOCR(uri);
}
}
}
//Function that begins the OCR functionality.
private void startOCR(Uri imgUri) {
try {
Log.e(TAG, "Inside the startOCR function");
BitmapFactory.Options options = new BitmapFactory.Options();
// 1 - means max size. 4 - means maxsize/4 size. Don't use value <4, because you need more memory in the heap to store your data.
options.inSampleSize = 4;
// FileOutputStream outStream = new FileOutputStream(String.valueOf(imgUri));
Bitmap bm = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imgUri);
// bm.compress(Bitmap.CompressFormat.PNG,100,outStream);
Bitmap bitmap = BitmapFactory.decodeFile(imgUri.getPath());
// bitmap = toGrayscale(bitmap);
//The result variable will hold whatever is returned from "extractText" function.
result = extractText(bm);
//Creating the intent to go to the CropTest
Intent intentToCropTest = new Intent(MainActivity.this, CropTest.class);
intentToCropTest.putExtra("result",result);
startActivity(intentToCropTest);
//Setting the string result to the content of the TextView.
// textView.setText(result);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
You are trying to treat Android Uri as file path. Don't do that. Instead retrive a ContentResolver instance and use it to convert Uri to stream:
AssetFileDescriptor fd = context.getContentResolver()
.openAssetFileDescriptor(uri, "r");
InputStream is = fd.createInputStream();
If AssetFileDescriptor is not supported (you get null or an Exception happens), try a more direct route:
InputStream is = context.getContentResolver().openInputStream();
There is also another super-duper powerful content-type-aware approach, which existed for ages, but was re-discovered by Google's own developers around the time of Android N release. It requires a lot more infrastructure on ContentProvider side (may not be supported in older versions of Google Services):
ContentResolver r = getContentResolver();
String[] streamTypes = r.getStreamTypes(uri, "*/*");
AssetFileDescriptor descriptor = r.openTypedAssetFileDescriptor(
uri,
streamTypes[0],
null);
InputStream is = descriptor.createInputStream();
Then use obtained stream to create Bitmap:
Bitmap bitmap = BitmapFactory.decodeStream(is);
Related
I'm using the following code to record the camera in Android that uses the basic Intent. How can I change it to use MediaRecorder API instead of this Intent-based approach?
private Uri fileUri;
//...
private void recordVideo() {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO);
// set video quality
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the image file
// start the video capture Intent
startActivityForResult(intent, CAMERA_CAPTURE_VIDEO_REQUEST_CODE);
}
// ...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE && resultCode == RESULT_OK) {
// play the video given the global fileUri
}
I don't use the Android SDK (my Java skills are on Windows only), but from a quick research...
See if this tutorial helps you (more info further beow)...
Just replace their audio setup (3GP) with the H264 & AAC setup from the other Question.
Also read the section about "Recording Video" on this article to understand the needed parts.
Also declare permissions in your Manifest.xml. An example of such manifest and related code is here on Github (that one allows RECORD_AUDIO but you need also a RECORD_VIDEO so set as):
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
Back to the tutorial, I cannot test their code but something like the below edit should get you started:
public class MainActivity extends Activity
{
MediaRecorder recorder;
File outputfile = null;
static final String TAG = "MediaRecording";
Then inside that class you add useful functions (initialise Recorder, start rec, stop rec, save file)...
public void initRecording(View view) throws IOException
{
//Creating file
File dir = Environment.getExternalStorageDirectory();
try { outputfile = File.createTempFile("video_test_android", ".mp4", dir); }
catch (IOException e)
{
Log.e(TAG, "external storage access error");
return;
}
//# Create a new instance of MediaRecorder
recorder = new MediaRecorder(); //create MediaRecorder object
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
//# Video settings
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); //contained inside MP4
recorder.setVideoSize(640, 480); //width 640, height 480
recorder.setVideoFrameRate(30); //30 FPS
recorder.setVideoEncodingBitRate(3000000); //adjust this for picture quality
//# Audio settings
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); //must always be AAC
recorder.setAudioEncoder(MediaRecorder.getAudioSourceMax());
recorder.setAudioEncodingBitRate(16);
recorder.setAudioSamplingRate(44100);
recorder.setOutputFile(outputfile.getAbsolutePath());
recorder.prepare();
}
public void startRecording(View view)
{
recorder.start();
}
public void stopRecording(View view)
{
recorder.stop(); recorder.release();
//# After stopping the recorder...
//# Create the video file and add it to the Media Library.
addRecordingToMediaLibrary();
}
protected void addRecordingToMediaLibrary()
{
//# used to store a set of values that the ContentResolver can process
ContentValues values = new ContentValues(4); //# 4 items (title, date, etc)
long current = System.currentTimeMillis(); //# get recording time (date)
//# size of 4 for values, all in String
values.put(MediaStore.Audio.Media.TITLE, "Android Tina J - " + outputfile.getName());
values.put(MediaStore.Audio.Media.DATE_ADDED, (int) (current / 1000));
values.put(MediaStore.Audio.Media.MIME_TYPE, "video/mp4"); //# set MIME type
values.put(MediaStore.Audio.Media.DATA, outputfile.getAbsolutePath()); // data stream for the file
//# provides applications access to the content model
ContentResolver contentResolver = getContentResolver();
//# The content:// style URI for the "primary" external storage volume.
Uri base = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Uri newUri = contentResolver.insert(base, values);
//# Request the media scanner to scan a file and add it to the media database
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri));
//# if you need a notification...
//Toast.makeText(this, "Created Media File : " + newUri, Toast.LENGTH_LONG).show();
}
So to begin a recording, just inititalise the media recorder and do a recorder.start(); to begin recording (camera and mic are used automatically according to your MediaRecorder settings).
I am currently working on an activity that will let the user select an image from the gallery, and then put that image's URI into an SQLite database.
I have another activity where I take that URI and display it on an ImageView. I have this working perfectly on Lollipop and older. But anything newer it crashes when I pull up the activity that displays the image.
Here is the LOGCAT line of the crash:
Caused by: java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord{8193e94 13574:jeremy.com.wineofmine/u0a97} (pid=13574, uid=10097) that is not exported from uid 10044
This makes it seem like a permissions thing, but I am requesting the WRITE_EXTERNAL_STORAGE and READ_EXTERNAL STORAGE in the manifest, as well as requesting those permissions on run-time on the activity where it displays the image.
And here is the exact line where it's crashing (this is in the activity where it displays the image:)
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageURI);
And this is imageURI:
imageURI = Uri.parse(cursor.getString(cursor.getColumnIndexOrThrow(WineContract.WineEntry.COLUMN_WINE_IMAGE)));
//This code returns this: content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F62/ACTUAL/860591124
Here is the code to the relevant bits.
This is the intent to open up the gallery:
Intent intentGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intentGallery, SELECT_IMAGE);
And this is the onActivityResult method. The main goal of this method is to set the imageThumbail ImageView as the thumbnail, and also to set "photoURI" as the selected image's URI.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//This is if they choose an image from the gallery
if (requestCode == SELECT_IMAGE && resultCode == RESULT_OK) {
if (requestCode == SELECT_IMAGE) {
// Get the url from data
Uri selectedImageUri = data.getData();
if (null != selectedImageUri) {
// Get the path from the Uri
String path = getPathFromURI(selectedImageUri);
Log.i("ADDACTIVITY", "Image Path : " + path);
bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);
} catch (IOException e) {
e.printStackTrace();
}
bitmapThumbnail = ThumbnailUtils.extractThumbnail(bitmap,175,175);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapThumbnail.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byteArray = stream.toByteArray();
// Set the image in ImageView
imageThumbnail.setImageBitmap(bitmapThumbnail);
//Setting photoURI (which gets put into the database) as the gallery's image URI
photoURI = data.getData();
}
}
}
}
Any pointers to what I could be doing wrong, would be great.
My attempt does not work at all unfortunately. Weirdly enough, capturing photos from camera works when debugging but does not in production.
#Override
public void onActivityResult(int requestCode, int resultCode, final Intent data) {
if (!Debug.isDebuggerConnected()){
Debug.waitForDebugger();
Log.d("debug", "started"); // Insert a breakpoint at this line!!
}
if (resultCode != RESULT_OK) {
return;
}
File file = null;
Uri path = null;
Bitmap image = null;
switch (requestCode) {
case RequestCodes.REQUEST_IMAGE_CAPTURE:
Bundle extras = data.getExtras();
image = (Bitmap) extras.get("data");
file = ImageUtils.saveToFile(image, "profile_picture", this);
mProfileImageView.setImageBitmap(image);
mCurrentAbsolutePath = file.getAbsolutePath();
break;
case RequestCodes.REQUEST_IMAGE_SELECT:
path = data.getData();
mProfileImageView.setImageURI(path);
mCurrentAbsolutePath = path.getPath();
file = new File(mCurrentAbsolutePath);
image = BitmapFactory.decodeFile(mCurrentAbsolutePath, new BitmapFactory.Options());
break;
default:
break;
}
try {
if(RequestCodes.REQUEST_IMAGE_SELECT == requestCode){
file = File.createTempFile(
"user_picture", /* prefix */
".jpeg", /* suffix */
getExternalFilesDir(Environment.DIRECTORY_PICTURES) /* directory */
);
File pathFile = new File(ImageUtils.getPath(path, this));
GeneralUtils.copy(pathFile, file);
}
} catch (IOException e) {
e.printStackTrace();
}
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(image, 100, 100);
String thumbnailPath = null;
// Edited source: https://stackoverflow.com/a/673014/6519101
FileOutputStream out = null;
try {
// PNG is a lossless format, the compression factor (100) is ignored
thumbnailPath = File.createTempFile(
"user_picture_thumbnail", /* prefix */
".png", /* suffix */
getExternalFilesDir(Environment.DIRECTORY_PICTURES) /* directory */
).getAbsolutePath();
out = new FileOutputStream(thumbnailPath);
thumbnail.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
String finalPath = file.getPath();
UserClient client = new UserClient();
String finalThumbnailPath = thumbnailPath;
client.changeUserPicture(file, FileUtils.getMimeType(this, Uri.fromFile(file)), new ApiListener<Response<ResponseBody>>(this){
#Override
public void onSuccess(Response<ResponseBody> response, int statusCode) {
SharedPreferencesManager preferences = SharedPreferencesManager.getInstance();
preferences.put(SharedPreferencesManager.Key.ACCOUNT_IMAGE_PATH, finalPath);
preferences.put(SharedPreferencesManager.Key.ACCOUNT_IMAGE_THUMBNAIL_PATH, finalThumbnailPath);
super.onSuccess(response, statusCode);
}
});
}
Unfortunately when debugging the from example of a path "/0/4/content://media/external/images/media/54257/ORIGINAL/NONE/1043890606" decoded file end up being null and breaks everything.
What is the best way of both getting from gallery and capturing image from photo?
What you should be using are content providers and resolvers here which can be thought of as databases and accessing databases for easier understanding.
That path you have there is called a URI, which is essentially like a link to a database entry. Both the camera and gallery uses content providers and resolvers actively. When a photo is taken, it is saved but the camera app also lets content provider know a new entry has been added. Now every app who has the content resolvers, such as the gallery app, can find that photo because the URI exist.
So you should be following the guides to implement content resolver if you want to access all photos in gallery.
As an aside, if you use code to copy an image file but does up update the content providers, your other app cannot see that new copied file unless it knows the absolute path. But when you restart your phone, some system does a full recheck for all image files and your content provider could be updated with the newly copied file. So try restarting your phone when testing.
Is there a way of looping through the default image gallery on an android device?
In my app I have managed to pass a selected picture from the default gallery to an imageView by this code:
public void onImageGalleryClicked(View v){
//Invoke image gallery using implicit intent
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
//Where is the image gallery stored
File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//Get path of the image gallery as string
CurrentPicturePath = pictureDirectory.getPath();
//Get the URI-representation of the image directory path
Uri data = Uri.parse(CurrentPicturePath);
//Set the data and type to get all the images
photoPickerIntent.setDataAndType(data, "image/*");
//Invoke activity and wait for result
startActivityForResult(photoPickerIntent, IMAGE_GALLERY_REQUEST);
}
And showing the picture in in a viewcontroller by:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK){
if(requestCode == IMAGE_GALLERY_REQUEST){
//Address of the image on SD-card
Uri imageUri = data.getData();
//Declare a stream to read the image from SD-card
InputStream inputStream;
try {
inputStream = getContentResolver().openInputStream(imageUri);
//Get a bitmap
Bitmap image = BitmapFactory.decodeStream(inputStream);
imgPicture.setImageBitmap(image);
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to open image!", Toast.LENGTH_LONG).show();
}
}
}
}
Now I want to have a button in my app that finds the next picture in the default gallery.
I'd like a way to loop through the gallery to find my current picture (by path/name!?) to be able to select the next one (or previous)
There are billions of Android devices, spread across thousands of device models. These will have hundreds of different "default image gallery" apps, as those are usually written by device manufacturers. The user does not have to use any of those apps to satisfy your ACTION_PICK request.
There is no requirement of ACTION_PICK implementations to supply you with "next" or "forward" information.
I want to be able to send a picture from one user to another in a messaging app like on whatsApp, but I am not sure how to do that. I am using android and parse as my DB. I tried googling and nothing seems to help, I am new on Android development. I would prefer to use it as I do with my texts , since when sending messages between users I am using parse as my database. Can someone please assist, I am able to select the image from galery and load it in an image view but I am not sure how to send it as I would with text. The code that should be under when the button "send" is clicked.
Below is the code that I have. Please have a look at it. I have been trying everything that I can think of but I am not getting anywhere.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
//Everything Okay
if (requestCode == LOAD_IMAGE_RESULTS) {
Uri pickedImage = data.getData();
InputStream inputStream;
try {
inputStream = getContentResolver().openInputStream(pickedImage);
Bitmap selectImage = BitmapFactory.decodeStream(inputStream);
sendPicture.setImageBitmap(selectImage);
selectImage = ((BitmapDrawable) sendPicture.getDrawable()).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
selectImage.compress(Bitmap.CompressFormat.PNG, 5, stream);
byte[] imageRec = stream.toByteArray();
final ParseObject imgMsgToBeSent = new ParseObject("SentImages");
final ParseFile fileRenamed;
//create parse file
fileRenamed = new ParseFile("SentImage.png", imageRec);
imgMsgToBeSent.put("receipientId", MessagingActivity.recipientId.toString());
imgMsgToBeSent.put("senderId", MessagingActivity.currentUserId.toString());
imgMsgToBeSent.put("imageReceived", fileRenamed);
sendImgBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.sendImageBtn) {
messageService.sendMessage(MessagingActivity.recipientId.toString(), fileRenamed.toString());
finish();
}
}
});
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),
"Unable to load image",
Toast.LENGTH_LONG).show();
}
}
}
}
For Sharing Image after selected from Gallery ##
First get the image path and than send it via intent like this:
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Uri Imageuri = Uri.fromFile(new File(image));
shareIntent.setType("image/");
shareIntent.putExtra(Intent.EXTRA_STREAM, Imageuri);
startActivity(Intent.createChooser(shareIntent, "ShareWia"));
for sharing image and text both just add one more settype and use put extra with text like this:
Intent shareIntent = new Intent(Intent.ACTION_SEND);
Uri Imageuri = Uri.fromFile(new File(image));
shareIntent.setType("image/");
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, text);
shareIntent.putExtra(Intent.EXTRA_STREAM, Imageuri);
startActivity(Intent.createChooser(shareIntent, "ShareWia"));
Sinch does not support attachments in IM