In my application, I am able to properly convert the drawable to an image and save it locally on the device. However, I'll need to push the image to Firebase and not save it locally. Here's what I have done.
public void saveImage () {
int count = 0;
File sdDirectory = Environment.getExternalStorageDirectory();
File subDirectory = new File(sdDirectory.toString() + "/Pictures/Paint");
if (subDirectory.exists()) {
File[] existing = subDirectory.listFiles();
for (File file : existing) {
if (file.getName().endsWith(".jpg") || file.getName().endsWith(".png")) {
count++;
}
}
} else {
subDirectory.mkdir();
}
if (subDirectory.exists()) {
File image = new File(subDirectory, "/drawing_" + (count + 1) + ".png");
FileOutputStream fileOutputStream;
try {
fileOutputStream = new FileOutputStream(image);
//The code below still doesn't save the image online in firebase.
Uri file = Uri.fromFile(image);
// StorageReference fileRef = reference.child(System.currentTimeMillis() + "." + getFileExtension(file));
StorageReference fileRef = reference.child(System.currentTimeMillis() + ".png");
fileRef.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
fileRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Model model = new Model(uri.toString());
String modelId = root.push().getKey();
root.child(modelId).setValue(model);
progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(getContext(), "Uploaded Successfully!", Toast.LENGTH_SHORT).show();
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getContext(), "Uploading Failed!", Toast.LENGTH_SHORT).show();
}
});
Boolean bool = mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
Toast.makeText(getContext(), "saved locally", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
}
It's always failing to upload the file but it successfully saves it locally. I've even just tried to display a notification upon a successful upload but it doesn't even get to the addOnSuccessListener talk less of the onSuccessMethod. I feel like I'm close but what could I be doing wrong?
Your code is ignoring all kinds of error, which make it really hard for you (let alone us) to troubleshoot.
First off: stop catching errors and doing nothing with them, like in } catch (FileNotFoundException e) {. At the very least you should log them with:
Log.e("Storage", "Error uploading image", e)
Same for the IOException, and for public void onFailure(#NonNull Exception e) {: if you log e there too, you may be able to find (in your logcat output) what is going wrong.
Related
I am using MediaMetadataRetriever as well as MLkit to do pose detection on a saved video file. I have attached some of my code here:
public ArrayList<ArrayList<Float>> extractPoses() throws FileNotFoundException {
//public Bitmap extractPoses() throws FileNotFoundException {
Log.e("DATA SOURCE: ", videoUri.getPath());
URIPathHelper uph = new URIPathHelper();
String videoInputPath = uph.getPath(applicationContext, videoUri).toString();
File vidInputFile = new File(videoInputPath);
File inputFile = new File(vidInputFile.getAbsolutePath());
if (!inputFile.canRead()) {
throw new FileNotFoundException("Unable to read $inputFile");
}
mdr.setDataSource(inputFile.getAbsolutePath());
ArrayList<ArrayList<Float>> totalVideoPose = new ArrayList<>();
int count = 0;
while (true) {
try {
Bitmap bmp = mdr.getFrameAtIndex(count);
InputImage inputImg = InputImage.fromBitmap(bmp, 0);
poseDetector.process(inputImg)
.addOnSuccessListener(new OnSuccessListener<Pose>() {
#Override
public void onSuccess(Pose pose) {
Log.e("POSE DETECT: ", "success");
if(!(pose.getAllPoseLandmarks().isEmpty())) {
ArrayList<Float> framePoseMarks = new ArrayList<Float>();
PoseLandmark left_shoulder = pose.getPoseLandmark(PoseLandmark.LEFT_SHOULDER);
framePoseMarks.add(left_shoulder.getPosition().x);
framePoseMarks.add(left_shoulder.getPosition().y);
totalVideoPose.add(framePoseMarks);
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e("POSE DETECT: ", "pose detect on failure listener");
}
});
Log.e("Pose processing: ", "incrementing count");
count++;
} catch (IllegalArgumentException e) {
Log.e("POSE DETEC:", "Pose detec ended");
Log.e("POSE DETEC length: ", String.valueOf(totalVideoPose.size()));
for (ArrayList<Float> frame: totalVideoPose) {
Log.e("POSE DETEC SUBS: ", String.valueOf(frame.size()));
}
break;
}
}
return totalVideoPose;
//return null;
}
I know the bitmaps I am using are correct, as I have displayed them in an ImageView to verify. I am not sure why neither is executing - I dont see the output for Log.e("POSE DETECT: ", "success"); or for Log.e("POSE DETECT: ", "pose detect on failure listener");. I appreciate any help and I am happy to answer any follow up questions!
I am using glide to extract a bitmap from the cache and save it elsewhere. The relevant function below (based on this post:) fails to trigger the extraction. In fact, the log line 'Log.d(TAG, "About to start extraction");' below never gets triggered.
Any ideas on why the simple target function never gets called?
public byte[] extractImageFromCache(Context context, String pictureURL) {
byte[] byteArray = new byte[0];
if (context != null && pictureURL != null && !pictureURL.isEmpty()) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Glide.with(context)
.load(pictureURL)
.asBitmap()
.toBytes()
.diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
.into(new SimpleTarget<byte[]>() {
#Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
Log.d(TAG, "About to start extraction");
new AsyncTask<Void, Void, Void>() {
#Override protected Void doInBackground(Void... params) {
Log.d(TAG, "Start extraction");
try {
Log.d(TAG, "Image bytes len: " + resource.length);
byteArrayOutputStream.write(resource);
byteArrayOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "Unable to load image: " + pictureURL);
e.printStackTrace();
}
return null;
}
}.execute();
}
});
Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL));
return byteArrayOutputStream.toByteArray();
}
return null;
}
As you have mentioned, Log.d(TAG, "About to start extraction") never gets triggered, which means onResourceReady never gets called. This could happen due to some error. Try overriding error callbacks.
To identify the problem I would recommend you to override other callbacks of SimpleTarget to debug the problem.
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
// load has been cleared
}
#Override
public void onLoadStarted(#Nullable Drawable placeholder) {
// load has started
}
#Override
public void onLoadFailed(#Nullable Drawable errorDrawable) {
// load failed due to some reason, notify callers here about the same
}
By using SimpleTarget object we can easily get Bitmap we are trying to extract from cache or network since by default glide look for cache hit.
Modify your Glide loading code to this :
Glide.with(this)
.load("https://cdn-images-1.medium.com/max/1200/1*hcfIq_37pabmAOnw3rhvGA.png")
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.d("Size ", "width :"+resource.getWidth() + " height :"+resource.getHeight());
imageView.setImageBitmap(resource);
storeImage(resource);
}
});
And Using this or any other mechanism for storing bitmap to external/internal storage.
private void storeImage(Bitmap image) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,
"Error creating media file, check storage permissions: ");// e.getMessage());
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
image.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
Log.d(TAG, "img dir: " + pictureFile);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
private File getOutputMediaFile(){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/Files");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
return null;
}
}
File mediaFile;
Random generator = new Random();
int n = 1000;
n = generator.nextInt(n);
String mImageName = "Image-"+ n +".jpg";
mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
return mediaFile;
}
I am using Glide ver 3.7
compile "com.github.bumptech.glide:glide:3.7.0"
Here is full working example : https://github.com/nieldeokar/GlideApp
First of all, your return is invalid because Glide executes the request in an asynchronous thread. So byteArrayOutputStream is never populated in time before the function returns. This means your function will always return an empty byte array. This also means your log statement Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL)); will be invalid. Knowing this, your About to start extraction will show up after Got image bytes.... You will need to reformat your code to use callbacks to notify the caller of the function that your code has retrieved the array. Something like this:
public interface GlideByteLoadCallback {
void onBytesExtracted(byte[] bytes);
void onFail(String message);
}
public void extractImageFromCache(Context context, String pictureURL, GlideByteLoadCallback callback) {
if (context != null && pictureURL != null && !pictureURL.isEmpty()) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Glide.with(context)
.load(pictureURL)
.asBitmap()
.toBytes()
.diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
.into(new SimpleTarget<byte[]>() {
#Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
Log.d(TAG, "About to start extraction");
new AsyncTask<Void, Void, Void>() {
#Override protected Void doInBackground(Void... params) {
Log.d(TAG, "Start extraction");
try {
Log.d(TAG, "Image bytes len: " + resource.length);
byteArrayOutputStream.write(resource);
byteArrayOutputStream.flush();
if (callback != null) callback.onBytesExtracted(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "Unable to load image: " + pictureURL);
e.printStackTrace();
if (callback != null) callback.onFail("Extraction failed");
}
}
}.execute();
}
});
}
if (callback != null) callback.onFail("Invalid url");
}
Then call it with:
extractImageFromCache(context, picture, new GlideByteLoadCallback() {
#Override
public void onFail(String message) {
// handle failure here
}
#Override
public void onBytesExtracted(byte[] bytes) {
// do stuff with bytes here
}
});
This is what I would do.
As you are using glide, place your loaded image to an Image view.
From code, set:
imageView = (ImageView) view.findViewById(R.id.image_view);
imageViewProfile.setDrawingCacheEnabled(true);
imageViewProfile.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
then to get the bitmap from that image view you can use
imageView.getDrawingCache() //This returns a Bitmap
The only thing you should worry about is to verify if Glide finished loading your image or not -I am not sure how to accomplish this-, but give a try and give a vote if this works for you.
When I try to save an image to an external directory, the directory is successfully scanned by MediaScannerConnection, but the images are not shown in gallery.
public void saveItem() {
if (selectCount == 0) {
Toast.makeText(getActivity(), "Select at least one image", Toast.LENGTH_SHORT).show();
} else {
Iterator iterator = selectedFile.iterator();
while (iterator.hasNext()) {
gridFilePath = new File(iterator.next().toString());
String destinationPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myImages/";
File destination = new File(destinationPath);
try {
FileUtils.copyFileToDirectory(gridFilePath, destination);
MediaScannerConnection.scanFile(getActivity(), new String[]{destinationPath},
null, new MediaScannerConnection.MediaScannerConnectionClient() {
#Override
public void onMediaScannerConnected() {
}
#Override
public void onScanCompleted(String path, Uri uri) {
Log.d("Scan","Scanning Completed");
}
}
);
Log.d("Image Saved", "Saved");
} catch (IOException e) {
e.printStackTrace();
}
}
Toast.makeText(getActivity(), "Pictures Saved", Toast.LENGTH_LONG).show();
}
}
I fixed my problem adding the file's mimeType:
private void notifyNewFileToSystem(File file) {
String type = null;
String extension = MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath());
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
MediaScannerConnection.scanFile(getApplicationContext(),
new String[]{file.getAbsolutePath()},
new String[]{type},
(path, uri) -> {
Log.e(TAG, "Path: " + path);
Log.e(TAG, "Uri: " + uri);
}
);
}
I found the solution to get the mimeType here:
https://stackoverflow.com/a/8591230/2077248
I want my program to download many images (around 500) from the internet and store them in my external storage. Currently when I download a single image, it shows a progressBar and downloads the image properly. However when I am trying to replicate w/ two images, it gives the Toast for "Download complete" for both images being downloaded, however no progressBar for either image is shown and only the first image is properly downloaded.
Here is the code for my onCreate method for activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove Title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//force portrait orientation. (No landscape orientation).
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_quran);
//Instantiate ProgressDialog (Used for downloading quran pages).
myProgressDialog = new ProgressDialog(QuranActivity.this);
myProgressDialog.setMessage("Downloading Quran");
myProgressDialog.setIndeterminate(true);
myProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
myProgressDialog.setCancelable(true);
//execute when the downloader must be fired.
final DownloadTask downloadTask = new DownloadTask(QuranActivity.this);
DownloadTask second = new DownloadTask(getApplicationContext());
myHTTPURL = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0001.jp2&scale=1&rotate=0";
myHTTPURL2 = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0002.jp2&scale=1&rotate=0";
//First check if the file has already been created. (Only need to download 1ce, or
//in the case where the user deleted the files, we reinstall them again).
if (isExternalStorageWritable()) {
File makeDirectory = getQuranStorageDir(QuranActivity.this, "Quran_Pages");
for (int i = 0; i < 2; i++) {
Bundle myBundle = new Bundle();
myBundle.putInt("i", i);
if (i == 0) {
downloadTask.execute(myHTTPURL);
try {
downloadTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
myProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true);
}
});
} else {
/*if (downloadTask.getStatus() == AsyncTask.Status.FINISHED) {
downloadTask.execute(myHTTPURL2);
} else if (downloadTask.getStatus() == AsyncTask.Status.RUNNING) {
try {
downloadTask.execute(myHTTPURL2).wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} */
second.execute(myHTTPURL2);
try {
second.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// downloadTask.execute(myHTTPURL2);
}
}
}
and this is the code for my AsynTask Class.
#TargetApi(Build.VERSION_CODES.FROYO)
private class DownloadTask extends AsyncTask {
private Context context;
private PowerManager.WakeLock myWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
//Display download percentage.
int fileLength = connection.getContentLength();
//create folder to place the downloaded file in.
// File Path:E:\Android\data\com.syedabdullah.syed.quran_memorization_application
// \files\Quran Memorization Application\Quran_Pictures
//So first create a root folder Quran Memorization Application then inside that
//folder we create another folder named Quran Pictures.
/* File rootFolder = new File(getExternalFilesDir("Quran Memorization Application"),
"Quran_Pages"); */
//Here we insert inside the Quran_Pictures folder the quran_pages.
//String myFileName = "quran_01.jpg";
Bundle y = new Bundle();
int retrievePos = y.getInt("i");
String quranFilePageName = "_" + retrievePos + ".jpg";
// String fileName = "justwork.jpg";
File sup = new File(getExternalFilesDir("Quran Memorization Application"), "Quran_Pages");
File myFile = new File(sup, quranFilePageName);
myFile.createNewFile();
//downlaod the file.
input = connection.getInputStream();
output = new FileOutputStream(myFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
//allow cancel with back button.
if (isCancelled()) {
input.close();
return null;
}
total += count;
//publish the progress.
if (fileLength > 0) {
publishProgress((int) (total * 100 / fileLength));
}
output.write(data, 0, count);
}
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(myFile));
QuranActivity.this.sendBroadcast(intent);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (connection != null) {
connection.disconnect();
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//Take CPU lock to prevent CPU from going off if the user presses the power button.
//during download.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
myWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
myWakeLock.acquire();
myProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
//If we get here length is known, so setIndertimante to false.
myProgressDialog.setIndeterminate(false);
myProgressDialog.setMax(100);
myProgressDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
myWakeLock.release();
myProgressDialog.dismiss();
if (result != null) {
Toast.makeText(context, "Download error: " + result, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Download Complete", Toast.LENGTH_SHORT).show();
}
}
} }
I was hoping to have a for loop that would create hundreds of downloadTasks and download all the images I need, and then I would call the get method. However in order for that to work, I first need too know why when I try for 2 images only the first one gets downloaded and why no progressbar shows up. Also if possible if I could get a hint as to how I can make my progressBar update for all the images and not be designed for just 1. Thanks in advance. (Note all URLs are currect.)
Thank you so much! figured out that my loops were suppose to go inside doInBackground. Also to anyone else having a similar issue. To download multiple files and display a decent progressBar, here is a very great tutorial: http://theopentutorials.com/tutorials/android/dialog/android-download-multiple-files-showing-progress-bar/
in my app I am trying to read a string out of a text file located online, and then save the contents to a variable. Here is my current code:
download.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
URL site = new URL("http://m.uploadedit.com/b029/1393133970157.txt");
Scanner s = new Scanner(site.openStream());
String num = s.nextLine();
}
catch(MalformedURLException e) {
e.printStackTrace();
}
catch(IOException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "String from file is: " + num,
Toast.LENGTH_LONG).show();
}
});
However this is giving me a force close. Here is the log: http://pastebin.com/2nsxmJz1
I believe that I need to implement an ASyncTask, but not sure how to go about doing so.
You can't use network communications on UI thread. As u correctly mentions you should use AsyncTask for such cases:
final AsyncTask<Object,Object,String> task = new AsyncTask<Object,Object,String>() {
protected String doInBackground(Object... o) {
try {
URL site = new URL("http://m.uploadedit.com/b029/1393133970157.txt");
Scanner s = new Scanner(site.openStream());
return s.nextLine();
}
catch(MalformedURLException e) {
throw new RuntimeException("Incorrect URL", e);
}
catch(IOException e) {
throw new RuntimeException("Can't fetch file content from url", e);
}
}
protected void onPostExecute(String r) {
Toast.makeText(getApplicationContext(), "String from file is: " + r,
Toast.LENGTH_LONG).show();
}
};
task.execute();