I have a method in a second class (Class2) where I pass in the values of context and uri from Class1. The second class (Class2) is a class where filters will be applied to images taken using the camera from Class1. The method in Class2 looks something like this
public void prepareImage(Context context, Uri uri) {
// BitmapFactory options
Options options = new Options();
options.inSampleSize = 2;
String path = uri.toString();
File file = new File(path);
FileInputStream fis = null; //initialize
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Bitmap img = BitmapFactory.decodeStream(fis);
Log.i(TAG, "Bitmap img: " + img);
//more code below, but above this comment is where the issue is
}
I am noticing that FileInputStream is returning null, therefore BitmapFactory.decodeStream is decoding nothing. There are two things that I think are issues but am not sure how to address them. First, I was wondering if I am receiving null for FileInputStream because I am using a path that is formed from uri.toString(). Or does that matter? The string path value is correct.
The second issue is that if my phone is tethered to the computer, after taking an image using my application, the image file does not seem to register until after I unplug the device from my computer. Only after I unplug my device from the computer does all my images come up in the gallery folder. So my suspicion is that file is not being found! There is evidence of this from logcat.
Anyway, I do not know how to get around this conflict. Maybe I need to save images in a different way. Here is how I am saving images in Class1.
File imgFileDir = getDir();
if (!imgFileDir.exists() && !imgFileDir.mkdirs()) {
Log.e(TAG, "Directory does not exist");
}
//Locale.US to get local formatting
SimpleDateFormat timeFormat = new SimpleDateFormat("hhmmss", Locale.US);
SimpleDateFormat dateFormat = new SimpleDateFormat("ddMMyyyy", Locale.US);
String time = timeFormat.format(new Date());
String date = dateFormat.format(new Date());
String photoFile = date + "_nameofapp_" + time + ".jpg";
String filename = imgFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(arg0);
fos.flush();
fos.close();
} catch (Exception e) {
Log.e(TAG, "Image could not be saved");
e.printStackTrace();
}
I also use a helper method
private File getDir() {
File sdDir = Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return new File(sdDir, "NameOfApp");
}
Lastly, I tried running the application untethered to my computer to see if it would work and it does not. The behavior is just the same, images that I take picture of does not show up in the gallery until I replug the device to my computer, and then all the images I took show up in the gallery. Why?
Per request, I am passing the URI from Class1 doing the following.
Class2 classTwo = new Class2();
classTwo.prepareImage(this, uri);
Just moving this to an answer so everyone can see:
It looks like an extra / got into your file Uri.
file:/storage/emulated/0 ...
versus
/file:/storage/emulated/0 ... (from the exception message)
:)
Related
In my android app, I use the Camera intent to click a photo and upload the same to my server for processing. However, there is a requirement that the resolution of the image should be more than 500X500.
The default camera resolution is much higher these days and hence the desired resolution is not an issue. However, in most cases the resolution is much higher and the image size comes up to 3 MB or so. Because of this, it takes longer to upload the image to server, especially in areas where internet connectivity is poor.
I would like to reduce the size of the image, preferably down to 100 KB or so, without reducing the resolution.
My code for capturing the image through intent is:
imageHolder = (ImageView)findViewById(R.id.cPhoto78);
imageHolder.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File outputFile1 = new File(getExternalStorageDirectory(), "/APDCLSBM/APDCL1.jpg");
outputFile1.delete();// Deletes the existing photo
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Toast.makeText(getBaseContext(),"Error in clicking picture",
Toast.LENGTH_SHORT).show();
finish();
}
Intent a = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (photoFile != null) {
Uri outputFileUri = FileProvider.getUriForFile(photoCamera.this,
BuildConfig.APPLICATION_ID + ".provider",
photoFile);
a.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(a, 1);
}
}
});
The following function creates the image file and path:
private File createImageFile() throws IOException {
String imageFileName = "APDCL1";
File storageDir = new File(
getExternalStorageDirectory() + IMAGE_DIRECTORY);
File image = new File(storageDir, imageFileName+".jpg");
currentPhotoPath = image.getAbsolutePath();
Log.d("path1",currentPhotoPath);
return image;
}
Please suggest a way
private File createImageFile() throws IOException {
String imageFileName = "APDCL1";
File storageDir = new File(
getExternalStorageDirectory() + IMAGE_DIRECTORY);
File image = new File(storageDir, imageFileName+".jpg");
try{
Bitmap bitmap = BitmapFactory.decodeFile(image.getAbsolutePath);
}catch(Exception e){ e.printStacktrace(); return null;}
File reducedSizeImage = new File.createTempFile("name",".jpg",location);
try ( FileOutputStream outputStream = new FileOutputStream(reducedSizeImage))
{
image.compress(Bitmap.CompressFormat.JPEG,20, outputStream); // this line will reduce the size , try changing the second argument to adjust to correct size , it ranges 0-100
} catch (Exception e) {
e.printStackTrace();
return null;
}
return reducedSizeImage // otherwise upload this file
}
Have a good day
Why is it not working?
Edit: added new versions of code & logs:
private void savePhotoFromCacheToFolder(Uri uri) {
File goodPhoto = album.setUpPhotoFile(); //new empty JPG
File currentPhoto = new File(uri.getPath()); //JPG from camera in cache
Log.v(TAG, "\ngoodPhoto Path " + goodPhoto);
Log.v(TAG, "\ncurrentPhoto Path " + currentPhoto);
FileInputStream source = null;
FileOutputStream destination = null;
try {
source = new FileInputStream(currentPhoto);
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "\ncurrentPhoto not found ");
}
try {
destination = new FileOutputStream(goodPhoto);
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "\ngoodPhoto not found ");
}
FileChannel sourceFileChannel = source.getChannel();
FileChannel destinationFileChannel = destination.getChannel();
long size = 0;
try {
size = sourceFileChannel.size();
sourceFileChannel.transferTo(0, size, destinationFileChannel);
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "\nshit happens ");
}
}
Logs:
V/MainActivity: goodPhoto Path /storage/emulated/0/Pictures/Good photos/IMG_20170222_113700_-913025224.jpg
V/MainActivity: currentPhoto Path /cache/photo.jpg
V/MainActivity: currentPhoto not found
java.lang.NullPointerException: Attempt to invoke virtual method 'java.nio.channels.FileChannel java.io.FileInputStream.getChannel()' on a null object reference
It looks like Uri is not correct, but this Uri was returned by Camera app. Or maybe I have no access to cache folder, but earlier I did preview photo using this Uri.
we have created an input stream and an output stream object. The input stream points to the current java file and the output stream is pointing to Output.java. It is to this Output.java we want the contents of the file to be transferred. As mentioned earlier, a file object is associated with a File Channel object. So, we obtain the File Channel object for both the input and the output stream using the following code,
public copyFile( String filePath ){
FileInputStream source = new FileInputStream(filePath );
FileOutputStream destination = new FileOutputStream("Output.java");
FileChannel sourceFileChannel = source.getChannel();
FileChannel destinationFileChannel = destination.getChannel();
long size = sourceFileChannel.size();
sourceFileChannel.transferTo(0, size, destinationFileChannel);
}
Compare your code with above code , there is difference of method for transferring data and while is not used here.
I am developing an Android app. In my app, I am uploading multiple images to server using Retrofit network library. Before I uploading file I create a temporary file from bitmaps. Then delete them after uploaded.
photoFiles = new ArrayList<File>();
MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
int index = 0;
for(Bitmap bitmap: previewBitmaps)
{
File file = null;
try{
String fileName = String.valueOf(System.currentTimeMillis())+".jpeg";
file = new File(Environment.getExternalStorageDirectory(), fileName); // create temporary file start from here
if(file.exists())
{
file.delete();
}
OutputStream os = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.close();
photoFiles.add(file);
requestBodyBuilder.addFormDataPart("files",file.getName(), RequestBody.create(MediaType.parse("image/png"),file));
}
catch (Exception e)
{
Toast.makeText(getBaseContext(),e.getMessage(),Toast.LENGTH_SHORT).show();
}
index++;
}
//Upload process goes here and delete files back after upload
Using above code, all working fine. But the problem is I have to create temporary files. I do not want to create temporary files. What I want to do is I create array list of Uri string when I pick up the file. Then on file upload, I will convert them to file back and do the upload process.
photoFiles = new ArrayList<File>();
MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
int index = 0;
for(Bitmap bitmap: previewBitmaps)
{
File file = null;
try{
Uri uri = Uri.parse(photosUriStrings.get(index));
file = new File(getPathFromUri(uri));
Toast.makeText(getBaseContext(),getPathFromUri(uri),Toast.LENGTH_SHORT).show();
photoFiles.add(file);
requestBodyBuilder.addFormDataPart("files",file.getName(), RequestBody.create(MediaType.parse("image/png"),file));
}
catch (Exception e)
{
Toast.makeText(getBaseContext(),e.getMessage(),Toast.LENGTH_SHORT).show();
}
index++;
}
As you can see in the above, I am converting the URI string back to file and then upload it. But this time retrofit unable to upload the file. File is not null as well. So I am pretty sure the error is with converting uri string back to image file back because my old code above working fine. Why can I not do that? How can I successfully convert from URI to image file back please?
I found this
Convert file: Uri to File in Android
and
Create File from Uri type android
both not working.
I am not clear about your question but I think this may help you. This single line code will help you to convert URI to file and show in your view.
Picasso.with(getContext()).load("URI path").into(holder.imgID);
I am a beginner android programmer. I create a project for hiding image. But, I have a problem in my project. Is that:
I use a method to move a photo from the folder A to folder .B(Here is how I hid it from image gallery) . I am sure that the picture in the folder A was deleted and moved to folder .B. However, when I open image gallery application I still see this picture is displayed at the folder A.
This is method copy picture to folder .B:
public static String copyFile(String path) {
//TO DO: create folder .B
File pathFrom = new File(path);
File pathTo = new File(Environment.getExternalStorageDirectory() + "/.B");
File file = new File(pathTo, fileToName);
while (file.exists()) {
fileToName = String.valueOf(System.currentTimeMillis());
file = new File(pathTo, fileToName);
}
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(pathFrom);
out = new FileOutputStream(file);
byte[] data = new byte[in.available()];
in.read(data);
out.write(data);
in.close();
out.close();
return file.getPath();
} catch (FileNotFoundException e) {
Log.e(TAG, e.getMessage());
return "error:" + e.getMessage();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
return "error:" + e.getMessage();
}
}
After copy picture to folder .B, I delete this picture in folder A:
new File(path).delete();
So Is there any suggestion for notify for all image gallery know that this picture was moved to another folder or another URI?
**UPDATE: The suggestion for me work fine is:
Before 4.4,you can call this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+Environment.getExternalStorageDirectory())));
After 4.4,try this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file)));
//the file is new image's path
THank FireSun and everyonce
After change imgae path,you should notify the gallery to update,so you should send a broadcast to make it.
Before 4.4,you can call this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse("file://"+Environment.getExternalStorageDirectory())));
After 4.4,try this:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + file)));
//the file is new image's path
Why don't you use
pathFrom.delete();
So in this app I made, The user makes a project and when they save, the number of frames is saved to numberFrames.txt on the SD card. Then I retrieve the file in another class. Only thing is that nFrames = 50 when i show a toast of nFrames to the screen after I run this code. The only initializing of nFrames I do is to zero right above this code, which is located in the onCreate().
File sdcardLocal = Environment.getExternalStorageDirectory();
File dir = new File (sdcardLocal.getAbsolutePath() + "/Flipbook/"+customizeDialog.getTitle()+"/");
dir.mkdirs();
File fileNum = new File(dir, "numberFrames.txt");
FileWriter myFileWriter = null;
try {
myFileWriter = new FileWriter(fileNum);
} catch (IOException e) {
e.printStackTrace();
}
BufferedWriter out = new BufferedWriter(myFileWriter);
try {
String text = bitmaps.size()+"";
out.write(text);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
I retrieve the file like this. I have no idea where this "50" value for nFrames came from as there are no loops around this and I know for sure that the particular project saved has only 3 frames. Why is this?
FileInputStream is = null;
BufferedInputStream bis = null;
try {
is = new FileInputStream(new File(mFolderDialog.getPath()+"/numberFrames.txt"));
bis = new BufferedInputStream(is);
nFrames = bis.read();
}catch (IOException e) {
e.printStackTrace();
}
You are writing out a string, and then reading the first byte as an integer. 50 is the ascii code for the '2' character.
You can use BufferedReader.readLine to read the entire first line of the file as a String, and then Integer.parseInt to convert that to an integer.
Also, I would take a closer look at your application's workflow. You don't give much information, but saving a file with a single integer value to the sdcard has a certain "smell" to it :). Have you looked at using a database, or maybe store the text file in your application's directory instead?