I want to reduce image file size before I upload it to firebase storage because it take long time to be uploaded.
This is a form which conatins edittext + imageview
I am saving the data(in realtime database) and the image(storage) at the same when clicking on "Save" button.
So how to do to reduce image size or compress it ??
public class PDV_form extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pdv_form);
imgproduit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectImage();
}
});
Save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rootNode = FirebaseDatabase.getInstance("https://dtechapp-94795-default-rtdb.europe-west1.firebasedatabase.app");
reference = rootNode.getReference().child("pdv");
String nomcmplt = nomCmplt.getEditText().getText().toString();
String nompdv = nomPdv.getEditText().getText().toString();
String phone = Phone.getEditText().getText().toString();
String adresse = Adresse.getEditText().getText().toString();
String commune = Commune.getEditText().getText().toString();
String wilaya = Wilaya.getEditText().getText().toString();
String codezip = Zip.getEditText().getText().toString();
String email = Email.getEditText().getText().toString();
String imagepdv = placeimgpdv.getDrawable().toString().trim();
UploadDialog = new ProgressDialog(PDV_form.this);
UploadDialog.setTitle("Sauvegarde en cours.... ");
UploadDialog.show();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.FRANCE);
Date now = new Date();
String fileName = formatter.format(now);
storageReference = FirebaseStorage.getInstance().getReference("pdv/" + fileName);
storageReference.putFile(imageUri)
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
placeimgpdv.setImageURI(null);
Toast.makeText(PDV_form.this, "Sauvegarde Terminée", Toast.LENGTH_SHORT).show();
if (UploadDialog.isShowing())
UploadDialog.dismiss();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (UploadDialog.isShowing())
UploadDialog.dismiss();
Toast.makeText(PDV_form.this, "Sauvegarde Annulée", Toast.LENGTH_SHORT).show();
}
});
StorageReference filpath = storageReference;
filpath.putFile(imageUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Task<Uri> downloadurl = taskSnapshot.getStorage().getDownloadUrl().addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull #NotNull Task<Uri> task) {
String t = task.getResult().toString();
DatabaseReference newPost = reference.child(nomcmplt + "(" + nompdv + ")");
newPost.child("nomcmplt").setValue(nomcmplt);
newPost.child("nompdv").setValue(nompdv);
newPost.child("phone").setValue(phone);
newPost.child("adresse").setValue(adresse);
newPost.child("commune").setValue(commune);
newPost.child("wilaya").setValue(wilaya);
newPost.child("codezip").setValue(codezip);
newPost.child("email").setValue(email);
newPost.child("imagepdv").setValue(task.getResult().toString());
newPost.child("user_id").setValue(uid);
if (task.isSuccessful()) {
startActivity(new Intent(PDV_form.this, Bottom_bar.class));
}
}
});
}
});
}
});
}
private void selectImage() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
// intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(intent, Gallery_code);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == Gallery_code && resultCode == RESULT_OK) {
imageUri = data.getData();
placeimgpdv.setImageURI(imageUri);
}
}
}
You are asking two questions, one is to reduce the size of the image and the other is to compress it. I am assuming you meant to compress the image in a lossy sort of way by reducing the size and not zip it. Let me know if that is not what you meant in the comments.
One option you have is to build a solution manually. Python has a bunch of good libraries that can help you do this, for java, I did find a few good resources that work along this direction, this SO question seems to be pretty good - How can I compress images using java?
Another option is to use a SaaS tool. This would really simplify the process for you and for something as simple as this, it probably won't even cost anything unless you are compressing a lot of images, or really really large images. As a starting point, you can check out TinyPNG - https://tinypng.com/. They have a developer API - https://tinypng.com/developers.
Edit: Based on new information regarding volume, updating my answer.
Since you are expecting a low amount of images, you can just use TinyPNG. It is pretty simple to get started. You can just sign up, and you get an API key. They have a nice API that you can use in Java - https://tinypng.com/developers/reference/java
I am trying to solve this as well and it appears nothing else is directly helpful to our situation.
The "Possible Duplicate" examples only works if you convert your image to a bitmap. Which almost all examples of what you are trying to achieve do so with bitmaps. Here is some code from that "duplicate" that should help you. Though after I implemented this, I had trouble dealing with rotation.
Uri selectedImageUri = data.getData();
Bitmap bmp = null;
try {
bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), selectedImageUri);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//here you can choose quality factor in third parameter(ex. i choosen 25)
bmp.compress(Bitmap.CompressFormat.JPEG, 25, baos);
byte[] fileInBytes = baos.toByteArray();
StorageReference photoref = chatPhotosStorageReference.child(selectedImageUri.getLastPathSegment());
//here i am uploading
photoref.putBytes(fileInBytes).addOnSuccessListener....etc
Now while this is probably the correct answer. I myself would prefer a cleaner solution that allows me to compress the file via both an InputStream or a Uri, as that is how I upload images to firebase storage as well.
I might be doing the same and dealing with the bitmap directly, but I intend to search for an alternative solution if I can.
To add there is this extension with firebase which will resize after you upload
Related
This question already has answers here:
How to use getdownloadurl in recent versions?
(5 answers)
How can i upload and retrieve an image to firebase storage in android in 2018 (taskSnapshot/getDownloadUrl deprecated) (Closed)
(3 answers)
Closed 2 years ago.
I have this code which uploads an image from imageview on the click of a button. Even if the image gets uploaded by this code, I'm unable to get the download url for the image which I can use in future reference purposes. Kindly help me in getting the download URL. FYI, the getDownloadURl() function has been deprecated and is not working. Thank you!
Button uploadBtn = findViewById(R.id.upload_btn);
uploadBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseStorage storage = FirebaseStorage.getInstance();
// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl("gs://'''''''.appspot.com/");
// Create a reference to "mountains.jpg"
StorageReference mountainsRef = storageRef.child(System.currentTimeMillis() + ".jpg");
// Create a reference to 'images/mountains.jpg'
StorageReference mountainImagesRef = storageRef.child("images" + System.currentTimeMillis() + ".jpg");
// While the file names are the same, the references point to different files
mountainsRef.getName().equals(mountainImagesRef.getName()); // true
mountainsRef.getPath().equals(mountainImagesRef.getPath()); // false
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = imageView.getDrawingCache();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] data = baos.toByteArray();
UploadTask uploadTask = mountainsRef.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle unsuccessful uploads
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
// taskSnapshot.getMetadata() contains file metadata such as size, content-type, and download URL.
String downloadUrl = taskSnapshot.getMetadata().getReference().getDownloadUrl().toString();
Toast.makeText(ClickImage.this, downloadUrl, Toast.LENGTH_SHORT).show();
}
});
}
});
I got this problem with me before, who gets to download Firebase correctly but not the link in downloadUrl.
After what I searched for the matter, there is a thing called AsyncTask and its method of work works to override the orders that need a greater period of time and executes the orders after it and when it is finished it returns to it
Solve this problem You can use this method to retrieve the value of downloadUrl
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
storageReference.getDownloadUrl().addOnCompleteListener(task -> {
String downloadUrl = Objects.requireNonNull(task.getResult()).toString();
});
I hope I simplified things for you and help you .
My app need to process input from PDF files consisting of text (mostly). I could do the parsing on my server, but I'd prefer not to. Anyway, after exploring my options for text extraction I found PDFBox library and its port to use with Android (https://github.com/TomRoush/PdfBox-Android)
In the app I show my users a standard UI for selecting the source document through ACTION_OPEN_DOCUMENT. Then override onActivityResult to get Uri - you know, the usual stuff.
The problem is that I can't figure out how to feed it to PDFBox. Since we're not talking "files" but rather "documents" and the lib wants a real file path. If I provide it with it for a certain file, the text parsing goes okay, but it's certainly not the best practice and it can't be done for all documents out there (cloud storage etc) so instead I do this:
InputStream inputStream = getContentResolver().openInputStream(uri);
and then read it line by line so in the end I can have it all in one string. Obviously, it works okay.
But how to actually input this data into PDFBox to do its text extraction magic? I can't find any docs on how to do it in a scenario when I don't have the "real file path".
Maybe there are better ways now? This library is quite old.. Basically I need to extract text from PDF and do it on an Android device, not through an API call. Really stuck here.
I needed similar functionality for my app so I've tried solution suggested by Mike M. in comments under your question and it worked great for me (so this is really his answer – I just confirmed that it works and supplied the code).
Hope it helps.
The “magic” is actually in these two lines:
InputStream inputStream = this.getContentResolver().openInputStream(fileUri);
document = PDDocument.load(inputStream);
But for some context (and for those who will search an answer for this problem on another occasion) here is whole example code:
public class MainActivity extends AppCompatActivity {
private static final int OPEN_FILE_REQUEST_CODE = 1;
Intent intentOpenfile;
Uri fileUri;
TextView tvTextDisplay;
Button bOpenFile;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTextDisplay = findViewById(R.id.tv_text_display);
PDFBoxResourceLoader.init(getApplicationContext());
bOpenFile = findViewById(R.id.b_open_file);
bOpenFile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
intentOpenfile = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intentOpenfile.setType("application/pdf");
startActivityForResult(intentOpenfile, OPEN_FILE_REQUEST_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == OPEN_FILE_REQUEST_CODE) {
if(resultCode == RESULT_OK) {
fileUri = data.getData();
PDDocument document = null;
String parsedText = null;
try {
InputStream inputStream = this.getContentResolver().openInputStream(fileUri);
document = PDDocument.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
try {
PDFTextStripper pdfStripper = new PDFTextStripper();
pdfStripper.setStartPage(0);
pdfStripper.setEndPage(1);
parsedText = "Parsed text: " + pdfStripper.getText(document);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (document != null) document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
tvTextDisplay.setText(parsedText);
}
}
}
}
I have an app where it is possible to create an user and this work perfectly and I am happy!
In a simple way, here is a method that adds the user to the Firebase database:
public void addUserInfoToDatabase(){
String user_id = mAuth.getCurrentUser().getUid();
final DatabaseReference the_user_database = FirebaseDatabase.getInstance().getReference().child("UserRegistraion").child(user_id);
Map userAttributes = new HashMap();
userAttributes.put("user_id", user_id);
userAttributes.put("username", userName);
userAttributes.put("name", name);
userAttributes.put("e-mail", email);
the_user_database.setValue(userAttributes);
if (mRegistrationListener != null)
mRegistrationListener.onRegistrationComplete(true); // Assumes success
}
And here is how the table looks when the user is registered:
What I want to do now is that I want the possibility to add a profile picture which belongs to each user: e,g a profile picture, family-picture etc.
The question is: how can i do this in Firebase? I am not asking anyone to do this for me, but just to give me a good tip or provide a guide/video for how to do this.
Thank you.
I usually create a separate activity for setting up a profile photo. Maybe instead of calling onRegistrationComplete call an onCompleteListener after setValue(userAttributes) like this:
the_user_database.setValue(userAttributes).addOnCompleteListener(new OnCompleteListener...){
Intent intent = new Intent(context, AddProfileActivity.class);
startActivity(intent);
In the next activity it could be a simple XML layout with a button and an ImageView.
This code can open your gallery, select an image, and place it in your imageview in the onActivityResult method:
private void selectPhotoFromGallery(){
Log.d(TAG, "selectPhotoFromGallery: started");
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, GALLERY_PICK);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == GALLERY_PICK){
if (resultCode == RESULT_OK && data != null){
contentUri = data.getData();
try{
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), contentUri);
profile_photo.setImageBitmap(bitmap);
}catch (IOException e){
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
}
You would then need a method to upload your image to FirebaseStorage and capture the downloadUrl to add to the desired node. In this case because you are adding to an existing node you call updateChildren() when adding the profile photo. I use a method like this:
private void uploadProfileImage(){
Log.d(TAG, "uploadProfileImage: uploading image....");
if (contentUri != null){
//from gallery
final StorageReference reference = FirebaseStorage.getInstance().getReference().child(currentUserID).child("profile_photo");
reference.putFile(contentUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
String profilePhotoUri = uri.toString();
DatabaseReference publicUserReference = FirebaseDatabase.getInstance().getReference().child("public_user")
.child(currentUserID);
HashMap hashMap = new HashMap();
hashMap.put("profile_photo", profilePhotoUri);
publicUserReference.updateChildren(hashMap).addOnCompleteListener(new OnCompleteListener() {
#Override
public void onComplete(#NonNull Task task) {
if (task.isSuccessful()){
Intent intent = new Intent(mContext, CompleteProfileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
}
});
}
});
}
});
}
}
You would need to adjust this for your specific needs obviously. The thing you are really trying to do is to save an image to Storage and get the http://... string location where it is stored and then insert that information into the same location as the previous information you provided.
I hope this counts as a helpful tip. https://www.youtube.com/watch?v=mPOhnTnLcSY That's a link to a video about uploading images to Firebase storage for more information if you need it. Good luck!
Whenever I make a continuous upload to Firebase, the latest photo that I upload will replace all the other link. it's a weird error and hard to believe.
get result image
String filePath = Environment.getExternalStorageDirectory() + "/image2.jpg";
selectedImageUri = Uri.parse(filePath);
imageView.setImageURI(selectedImageUri);
ImageCompression imageCompression = new ImageCompression(this);
String oath = imageCompression.compressImage(filePath);
uriN = Uri.fromFile(new File(oath));
upload the image
private void fabSend(){
if (uriN!=null){
final StorageReference photoRef = storageRef.child(selectedImageUri.getLastPathSegment() + ".jpg");
photoRef.putFile(uriN).addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() {
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
image = (downloadUrl.toString());
postRef.push().setValue(new myAdapter(image,
description ,
user.getDisplayName())).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
progress.setVisibility(View.GONE);
imageView.setImageBitmap(null);
uriN = null;
fab.setVisibility(View.VISIBLE);
}
});
}
});}
The fact is if I quit the activity and relaunch it again, this does not happen. I have tried using reCreate() but the same happens.
All links are different ie different upload tokens and different images
but the last picture that is uploaded is the one shown for all links.
That's because you're stating that all images must have the same name (image2.jpg) in this line:
String filePath = Environment.getExternalStorageDirectory() + "/image2.jpg";
What you should do instead is get the Uri from the data parameter in onActivityResult() (I assume that's were you're getting the image result:
selectedImageUri = data.getData();
imageView.setImageURI(selectedImageUri);
ImageCompression imageCompression = new ImageCompression(this);
String oath = imageCompression.compressImage(filePath);
uriN = Uri.fromFile(new File(oath));
Edit: You can change the name before sending it to Firebase Storage, maybe adding date and time. Like this:
String newName = new SimpleDateFormat("yyyy-MM-dd-HHmm").format(new Date());
final StorageReference photoRef = storageRef.child("IMG-"+newName+ ".jpg");
I upload an image to Firebase Storage with Android. I have an app which send image immediately after captured a photo.
But I would like to create an app which show a photo in ImageView before sending. I'd like to write some text under the photo and next, upload both of them.
Which tools should I use to do this?
I've Picasso to download from Storage. But I can't manage how to show an ImageView after capturing a photo, next write some text(like name or description) and send it to Firebase.
The second challenge is how to show particular text with this image?
IMAGE <-> TEXT.
In Firebase Storage I don't see some field to store image with a text.
MainActivity.java:
private ProgressDialog mProgress;
private Bitmap bitmap;
private Button mUploadBtn;
private Button mSendBtn;
private EditText mEditText;
private ImageView mImageView;
Uri picUri;
private StorageReference mStorage;
private static final int CAMERA_REQUEST_CODE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStorage = FirebaseStorage.getInstance().getReference();
mEditText = (EditText) findViewById(R.id.editText);
mSendBtn = (Button) findViewById(R.id.sendBtn);
mUploadBtn = (Button) findViewById(R.id.uploadBtn);
mImageView = (ImageView) findViewById(R.id.imageView);
mProgress = new ProgressDialog(this);
mUploadBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File file=getOutputMediaFile(1);
picUri = Uri.fromFile(file); // create
i.putExtra(MediaStore.EXTRA_OUTPUT,picUri); // set the image file
startActivityForResult(i, CAMERA_REQUEST_CODE);
}
});
}
public void UploadWithText(){
String name = mEditText.getText().toString().trim();
}
/** Create a File for saving an image */
private File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyApplication");
/**Create the storage directory if it does not exist*/
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
return null;
}
}
/**Create a media file name*/
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == 1){
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".png");
} else {
return null;
}
return mediaFile;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CAMERA_REQUEST_CODE && resultCode == RESULT_OK ) {
mProgress.setMessage("Uploading Image...");
mProgress.show();
Uri uri = picUri;
StorageReference filepath = mStorage.child("Photos").child(uri.getLastPathSegment());
filepath.putFile(uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
mProgress.dismiss();
Uri downloadUri = taskSnapshot.getDownloadUrl();
Picasso.with(MainActivity.this).load(downloadUri).fit().centerCrop().into(mImageView);
Toast.makeText(MainActivity.this, "Uploaded Successfully.", Toast.LENGTH_LONG).show();
}
});
}
}
Maybe there is a way that I can send the image to Firebase Storage but a Text(description) is sending to Database with a Name field(from Firebase Storage) and with this I can recognize which Text belongs to a particular image?
Could somebody help me to resolve this challenge?
Regards
I can only answer broadly, since there's a bit too much code to answer specifically without doing it for you. In general, there are few ways to do this:
Add text to the image file itself, upload the new image with changes made
Store text as an image attribute, upload the file and save attributes elsewhere
You can either store the data in the Realtime Database, or
You can store the data in Storage file metadata (assuming pairs)