I'd like to share GIFs I loaded with Glide but i can't find a way to do it.
I tried to share the GifDrawable data as an array of byte but when i try to share, the GIF doesn't appear.
Here's the code I wrote :
Glide.with(getActivity())
.load(to_add.mMeme.getmUrl())
.asGif()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.transformFrame(new TextTransformation(getContext(), to_add.mMeme.getmText()))
.listener(new RequestListener<String, GifDrawable>() {
#Override
public boolean onException(Exception e, String s, Target<GifDrawable> target, boolean b) {
return false;
}
#Override
public boolean onResourceReady(GifDrawable gifDrawable, String s, Target<GifDrawable> target, boolean b, boolean b1) {
to_add.mDrawable = gifDrawable;
to_add.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Meme to_share = null;
for (Meme meme : mViewList) {
if (meme.mView.equals(v)) {
to_share = meme;
break;
}
}
if (to_share != null) {
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/*");
shareIntent.putExtra(Intent.EXTRA_STREAM, to_share.mDrawable.toString());
startActivity(Intent.createChooser(shareIntent, "Share"));
}
}
});
return false;
}
})
.into((ImageView) to_add.mView.findViewById(R.id.memeImageView));
Here is my Meme class used in the previous code :
public static class Meme {
public Meme(StorageManager.Meme meme, View view) {
mMeme = meme;
mView = view;
}
StorageManager.Meme mMeme;
View mView;
GifDrawable mDrawable;
}
mViewList is a List of Meme:
List<Meme> mViewList;
And to_add variable is the Meme containing the GIF i'm trying to share :
final Meme to_add = new Meme(data, getActivity().getLayoutInflater().inflate(R.layout.meme_layout, null));
I miss understood how to use share intents.
Sharing with intents
To answer my question, sharing a file with a Share intent require the file to be accessible on drive.
That's why I had to write it in the cache memory using :
File file = new File(mContext.getExternalCacheDir(), myMeme.getmFileName());
file.setReadable(true);
Don't write your file in your App cache dir, otherwise file will not be accessible by other applications
mContext.getCacheDir()
Then I could easily share my File using Uris :
Uri uri = Uri.fromFile(file);
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("image/gif");
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(shareIntent, "Share with"));
Sharing works perfectly now.
Concerning Glide GIF
I wasn't able to get Glide transformed GIF.
To add my text to the GIF, i splitted all frames composing the GIF and writted down the text.
Split GIF into frames using Glide
GifDecoder decoder = mGif.getmDrawable().getDecoder();
Bitmap frame;
Log.d("GIF GENERATION", "STARTED FRAME SPLIT");
int max = mGif.getmDrawable().getFrameCount();
int current = 0;
decoder.advance();
while (current < max && (frame = decoder.getNextFrame()) != null) {
Log.d("GIF GENERATION", "ADDED FRAME");
// Here you get your GIF frame per frame
decoder.advance();
current++;
}
Log.d("GIF GENERATION", "ENDED FRAME SPLIT");
Adding text to every frame
To write down my text on every frame, I used this class that works perfectly for single line text : http://www.skoumal.net/en/android-how-draw-text-bitmap/
Creating new GIF with frames
To do that, I used another class called GifCreator. It can be found here : https://github.com/nbadal/android-gif-encoder
Final Result
Here's how the actual code is :
GifDecoder decoder = mGif.getmDrawable().getDecoder();
GifCreator creator = new GifCreator();
Bitmap frame;
creator.start(mOs);
creator.setSize(mGif.getmDrawable().getDecoder().getWidth(), mGif.getmDrawable().getDecoder().getHeight());
creator.setRepeat(0);
creator.setQuality(15);
Log.d("GIF GENERATION", "STARTED FRAME SPLIT");
int max = mGif.getmDrawable().getFrameCount();
int current = 0;
decoder.advance();
while (current < max && (frame = decoder.getNextFrame()) != null) {
Log.d("GIF GENERATION", "ADDED FRAME");
creator.addFrame(TextTransformation.drawTextToBitmap(mContext, temp, mText));
creator.setDelay(decoder.getNextDelay());
decoder.advance();
current++;
}
Log.d("GIF GENERATION", "ENDED FRAME SPLIT");
creator.finish();
Related
I'm trying to get fresco cached image from a fragment after a button click event to share the image bitmap in whatsapp!! Unfortunately it's very slow, after click the share button 2, 3 times code works!! I'm looking for better solution !!
ImageRequest imageRequest = ImageRequestBuilder
.newBuilderWithSource(Uri.parse("http://example.com/test,jpg"))// disck cached
.setRequestPriority(com.facebook.imagepipeline.common.Priority.HIGH)
.setLowestPermittedRequestLevel(ImageRequest.RequestLevel.DISK_CACHE)
.build();
// .setRequestPriority(Priority.HIGH)
DataSource<CloseableReference<CloseableImage>> dataSource =
imagePipeline.fetchDecodedImage(imageRequest, this);
try {
dataSource.subscribe(new BaseBitmapDataSubscriber() {
#Override
public void onNewResultImpl(#Nullable Bitmap bitmap) {
if (bitmap == null) {
Log.d(TAG, "Bitmap data source returned success, but bitmap null.");
return;
}
sharewithwhatsappBitmap(bitmap);
// The bitmap provided to this method is only guaranteed to be around
// for the lifespan of this method. The image pipeline frees the
// bitmap's memory after this method has completed.
//
// This is fine when passing the bitmap to a system process as
// Android automatically creates a copy.
//
// If you need to keep the bitmap around, look into using a
// BaseDataSubscriber instead of a BaseBitmapDataSubscriber.
}
#Override
public void onFailureImpl(DataSource dataSource) {
// No cleanup required here
Log.d(TAG, "Bitmap data source onFailureImpl");
}
}, CallerThreadExecutor.getInstance());
} finally {
if (dataSource != null) {
dataSource.close();
}
}
I'm using DraweeController in recyclerview, DraweeController is more optimized I guess !! but don't how to use it for getting one image with bitmap !!
public void sharewithwhatsappBitmap(Bitmap bitmap) {
String path = MediaStore.Images.Media.insertImage(getApplicationContext().getContentResolver(),
bitmap, "Image Description", null);
Uri bmpUri = Uri.parse(path);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, bmpUri);
//shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Title Of The Post");
shareIntent.putExtra(Intent.EXTRA_TEXT, "https://play.google.com/store/apps/details?id=garbagebin.com.garbagebin");
shareIntent.setType("image/*");
//startActivity(Intent.createChooser(shareIntent, "Share Image"));
shareIntent.setPackage("com.whatsapp");
try {
startActivity(shareIntent);
} catch (android.content.ActivityNotFoundException ex) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.whatsapp")));
}
}
Log when first time it calls for bitmap:
v/unknown:AbstractDraweeController: controller 2a7f5b0e null -> 15: initialize
V/unknown:AbstractDraweeController: controller 2a7f5b0e 15: setHierarchy: com.facebook.drawee.generic.GenericDraweeHierarchy#20cc392f
Can any body tell me how can i share GIF image in android programmatically like.
Actually i want to share GIF image like android share .jpg or .png images.
I search a lot of but there is no link to share GIF image,please if anybody know please tell me.
code for sharing GIF image? startActivity(Intent.createChooser(shareIntent,"Share Emoji")); is used to share data using intent with the title "Share Emoji" whenever we share jpg or png it works perfectly. But if we try to send GIF images it does not work perfectly only email way works, if we select any other app to share GIF image like WhatsApp or Shareit, it converts GIF image to simple png image..... By this code only, i am unable to share GIF image with every other apps. So please check it and give me reasonable & practical solution if this is possible
Thank you
===============================================================
this is my code which i used currently
public class SplashScreen extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_main);
Button click = (Button) findViewById(R.id.click);
click.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
shareGif(getResources().getResourceName(R.drawable.clark));
}
});
}
private void shareGif(String resourceName) {
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "sharingGif.gif";
File sharingGifFile = new File(baseDir, fileName);
try {
byte[] readData = new byte[1024 * 500];
InputStream fis = getResources().openRawResource(getResources().getIdentifier(resourceName, "drawable", getPackageName()));
FileOutputStream fos = new FileOutputStream(sharingGifFile);
int i = fis.read(readData);
while (i != -1) {
fos.write(readData, 0, i);
i = fis.read(readData);
}
fos.close();
} catch (IOException io) {
}
System.out.println("===sharing file=="+sharingGifFile);
Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
shareIntent.setType("image/gif");
Uri uri = Uri.fromFile(sharingGifFile);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(shareIntent, "Share Emoji"));
}
}
I'm currently working on a project of capturing an image, cropping the image, processing the image then saving the processed image. My problem lies in saving the processed image. I can't save the processed image. For every image that is captured, the captured image is being shown in the gallery instead of the processed image. I'm thinking that because the capturing image code saves the image to the SD card, I can't save the processed image that is on a bitmap... I hope you can enlighten me on what is the problem of my code. There is no error on the code by the way.
To be a little more specific, the app I'm working with captures image then crops the image. After that image will be shown in imageView. When processed, it will be again shown in an imageView. when i get the image to save in the external storage, nothing happens...
Here is the code for capturing and cropping the image
public class MainActivity extends Activity {
ImageView mainImageview;
Button mainButtonTakePhoto;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeControls();
}
private void initializeControls() {
mainImageview = (ImageView)findViewById(R.id.imageView1);
mainButtonTakePhoto = (Button)findViewById(R.id.button3);
mainButtonTakePhoto.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
/* create an instance of intent
* pass action android.media.action.IMAGE_CAPTURE
* as argument to launch camera */
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
/*create instance of File with name img.jpg*/
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
/*put uri as extra in intent object*/
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
/*start activity for result pass intent as argument and request code */
startActivityForResult(intent, 1);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//if request code is same we pass as argument in startActivityForResult
if(requestCode==1){
//create instance of File with same name we created before to get image from storage
File file = new File(Environment.getExternalStorageDirectory()+File.separator + "img.jpg");
//Crop the captured image using an other intent
try {
/*the user's device may not support cropping*/
cropCapturedImage(Uri.fromFile(file));
}
catch(ActivityNotFoundException aNFE){
//display an error message if user device doesn't support
String errorMessage = "Sorry - your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
if(requestCode==2){
//Create an instance of bundle and get the returned data
Bundle extras = data.getExtras();
//get the cropped bitmap from extras
Bitmap thePic = extras.getParcelable("data");
//set image bitmap to image view
mainImageview.setImageBitmap(thePic);
}
}
//create helping method cropCapturedImage(Uri picUri)
public void cropCapturedImage(Uri picUri){
//call the standard crop action intent
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri of image
cropIntent.setDataAndType(picUri, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 0);
cropIntent.putExtra("aspectY", 0);
//indicate output X and Y
cropIntent.putExtra("outputX", 128);
cropIntent.putExtra("outputY", 256);
//retrieve data on return
cropIntent.putExtra("return-data", true);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, 2);
}
}
And here is the code for saving the image.
public void saveImageToExternalStorage(Bitmap finalBitmap) {
String root =Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";
File file1 = new File(myDir, fname);
if (file1.exists())
file1.delete();
try {
FileOutputStream out = new FileOutputStream(file1);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
}
catch (Exception e) {
e.printStackTrace();
}
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(this, new String[] { file1.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
}
Thanks a lot for your help. I'm trying not to trouble anyone if this is a stupid question. And I'm really trying my best to research and study every part of the code I'm using/lifting... Thanks again...
Are you testing it on api23 and up? If so... are you manually requesting permission to WRITE_EXTERNAL_STORAGE? because putting it in manifest is not enough.
The code works just fine... I'm sorry to waste all of your time and concern...
I just added the manifest to write to memory...
When I read from android developers about the manifest for writing to storage, I thought there is no need for the manifest when you are using API19 and up...
In my code I allow user to upload photos from gallery or from camera. Then image is stored into the server through retrofit. When retrieved the photo is always rotated 90 degrees if the photo is taken using the phone's camera (regardless whether it is from invoked through the app or invoked through the camera directly). If the images are not taken using the camera, the orientation is correct. How do I resolve this?
I know if I tried to display the image directly without storing it in server, and it was possible to be in the right orientation because I could rotate it before displaying. I am doing something similar to the codes here: https://gist.github.com/Mariovc/f06e70ebe8ca52fbbbe2.
But because I need to upload to the server and then retrieve from the server again. How do I rotate it before storing to the server so that when I retrieve it, it is already in the right orientation?
Below is some parts of my codes (just some usual handling of images and displayAvatarInProfile() is called after the service finished the downloading of image):
public void displayAvatarInProfile(String filePath) {
if(filePath != null && filePath != ""){
int targetW = mProfilePicImageView.getWidth();
int targetH = mProfilePicImageView.getHeight();
Bitmap bm = ImageStorageUtils.resizePic(filePath, targetW, targetH);
mProfilePicImageView.setImageBitmap(bm);
} else {
mProfilePicImageView.setImageBitmap(null);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK) {
Uri fileUri = null;
String filePath = null;
switch(requestCode) {
case REQUEST_PICK_IMAGE:
fileUri = data.getData();
break;
case REQUEST_CAPTURE_IMAGE:
File imageFile = ImageStorageUtils.getFile(
getActivity().getResources().getString(R.string.ApptTitle),
"avatar_" + mUser.getLogin());
filePath = imageFile.getAbsolutePath();
fileUri = ImageStorageUtils.getUriFromFilePath(mContext.get(), filePath);
break;
default:
break;
}
if(fileUri != null) {
getActivity().startService(ProfileService.makeIntentUploadAvatar(
mContext.get(), mUser.getId(), fileUri));
}
}
}
public void pickImage() {
final Intent imageGalleryIntent =
new Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI)
.setType("image/*")
.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
// Verify the intent will resolve to an Activity.
if (imageGalleryIntent.resolveActivity(getActivity().getPackageManager()) != null)
// Start an Activity to get the Image from the Image Gallery
startActivityForResult(imageGalleryIntent,
DisplayProfileFragment.REQUEST_PICK_IMAGE);
}
public void captureImage() {
Uri captureImageUri = null;
try {
captureImageUri = Uri.fromFile(ImageStorageUtils.createImageFile(
mContext.get(),
getActivity().getResources().getString(R.string.ApptTitle),
"avatar_" + mUser.getLogin()));
} catch (IOException e) {
e.printStackTrace();
}
// Create an intent that will start an Activity to get
// capture an image.
final Intent captureImageIntent =
new Intent(MediaStore.ACTION_IMAGE_CAPTURE)
.putExtra(MediaStore.EXTRA_OUTPUT, captureImageUri);
// Verify the intent will resolve to an Activity.
if (captureImageIntent.resolveActivity(getActivity().getPackageManager()) != null)
// Start an Activity to capture an image
startActivityForResult(captureImageIntent,
DisplayProfileFragment.REQUEST_CAPTURE_IMAGE);
}
Update 1
Was commented that I needed more description:
When I am uploading a file, I do this:
boolean succeeded = mImpatientServiceProxy.uploadAvatar(userId, new TypedFile("image/jpg", imageFile));
When I download, I get a retrofit.client.Response object, which I then get the InputStream from the Response and write the data to a file using an Output Stream.
final InputStream inputStream = response.getBody().in();
final OutputStream outputStream = new FileOutputStream(file);
IOUtils.copy(inputStream, outputStream);
Update 2
This is not a duplicate of existing solution because the user can upload from gallery, you do not know if it is a photo taken from resources online or from camera, so you cannot rotate the image when you display it.
Use camera api instead of intent. When you capture image using intents it displays rotated. In camera api there are methods by which you can change the rotation of the camera as well as the captured photo too.
I want to start the camera intent within my app to take a picture and save it to internal storage. I'm using the code of google developers page Capturing images or video.
In the processPictureWhenReady method I've implemented the following code to save the picture:
private void processPictureWhenReady(final String picturePath) {
Log.v("path processPictureWhenReady ", " " + picturePath);
final File pictureFile = new File(picturePath);
if (pictureFile.exists()) {
// The picture is ready; process it.
try {
Bitmap imageBitmap = BitmapFactory.decodeFile(picturePath);
int w = imageBitmap.getWidth();
int h = imageBitmap.getHeight();
Bitmap bm2 = Bitmap.createScaledBitmap(imageBitmap, w / 2,
h / 2, true);
imageBitmap = bm2.copy(bm2.getConfig(), true);
MediaStore.Images.Media.insertImage(getContentResolver(),
imageBitmap, "test", "Test");
} catch (Exception e) {
Log.e("Exc", e.getMessage());
}
}
The camera intent is starting and then I have "tap to accept" to take a picture. But then nothing happens. I have a log message in my onActivityResult method and noticed that the method is not beeing called.
This is a known issue. I have the same problem. I'm following the case here in the meantime
I've seen people try implementing the preview mode with SurfaceView (I haven't personally gotten it to work but it's worth a shot). Also check here for a similar problem.
I used this method it worked for me very well.
private void processPictureWhenReady(final String picturePath) {
final File pictureFile = new File(picturePath);
if(pictureFile.exists()){
}
if (pictureFile.exists()) {
} else {
final File parentDirectory = pictureFile.getParentFile();
FileObserver observer = new FileObserver(parentDirectory.getPath()) {
private boolean isFileWritten;
#Override
public void onEvent(int event, String path) {
if (!isFileWritten) {
// For safety, make sure that the file that was created in
// the directory is actually the one that we're expecting.
File affectedFile = new File(parentDirectory, path);
isFileWritten = (event == FileObserver.CLOSE_WRITE && affectedFile.equals(pictureFile));
if (isFileWritten) {
stopWatching();
// Now that the file is ready, recursively call
// processPictureWhenReady again (on the UI thread).
runOnUiThread(new Runnable() {
#Override
public void run() {
processPictureWhenReady(picturePath);
}
});
}
}
}
};
observer.startWatching();
}
}