-
-
Save samkirton/0242ba81d7ca00b475b9 to your computer and use it in GitHub Desktop.
package com.memtrip; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import android.content.ContentResolver; | |
import android.content.ContentUris; | |
import android.content.ContentValues; | |
import android.graphics.Bitmap; | |
import android.graphics.Matrix; | |
import android.net.Uri; | |
import android.provider.MediaStore; | |
import android.provider.MediaStore.Images; | |
/** | |
* Android internals have been modified to store images in the media folder with | |
* the correct date meta data | |
* @author samuelkirton | |
*/ | |
public class CapturePhotoUtils { | |
/** | |
* A copy of the Android internals insertImage method, this method populates the | |
* meta data with DATE_ADDED and DATE_TAKEN. This fixes a common problem where media | |
* that is inserted manually gets saved at the end of the gallery (because date is not populated). | |
* @see android.provider.MediaStore.Images.Media#insertImage(ContentResolver, Bitmap, String, String) | |
*/ | |
public static final String insertImage(ContentResolver cr, | |
Bitmap source, | |
String title, | |
String description) { | |
ContentValues values = new ContentValues(); | |
values.put(Images.Media.TITLE, title); | |
values.put(Images.Media.DISPLAY_NAME, title); | |
values.put(Images.Media.DESCRIPTION, description); | |
values.put(Images.Media.MIME_TYPE, "image/jpeg"); | |
// Add the date meta data to ensure the image is added at the front of the gallery | |
values.put(Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000); | |
values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis()); | |
Uri url = null; | |
String stringUrl = null; /* value to be returned */ | |
try { | |
url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); | |
if (source != null) { | |
OutputStream imageOut = cr.openOutputStream(url); | |
try { | |
source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut); | |
} finally { | |
imageOut.close(); | |
} | |
long id = ContentUris.parseId(url); | |
// Wait until MINI_KIND thumbnail is generated. | |
Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id, Images.Thumbnails.MINI_KIND, null); | |
// This is for backward compatibility. | |
storeThumbnail(cr, miniThumb, id, 50F, 50F,Images.Thumbnails.MICRO_KIND); | |
} else { | |
cr.delete(url, null, null); | |
url = null; | |
} | |
} catch (Exception e) { | |
if (url != null) { | |
cr.delete(url, null, null); | |
url = null; | |
} | |
} | |
if (url != null) { | |
stringUrl = url.toString(); | |
} | |
return stringUrl; | |
} | |
/** | |
* A copy of the Android internals StoreThumbnail method, it used with the insertImage to | |
* populate the android.provider.MediaStore.Images.Media#insertImage with all the correct | |
* meta data. The StoreThumbnail method is private so it must be duplicated here. | |
* @see android.provider.MediaStore.Images.Media (StoreThumbnail private method) | |
*/ | |
private static final Bitmap storeThumbnail( | |
ContentResolver cr, | |
Bitmap source, | |
long id, | |
float width, | |
float height, | |
int kind) { | |
// create the matrix to scale it | |
Matrix matrix = new Matrix(); | |
float scaleX = width / source.getWidth(); | |
float scaleY = height / source.getHeight(); | |
matrix.setScale(scaleX, scaleY); | |
Bitmap thumb = Bitmap.createBitmap(source, 0, 0, | |
source.getWidth(), | |
source.getHeight(), matrix, | |
true | |
); | |
ContentValues values = new ContentValues(4); | |
values.put(Images.Thumbnails.KIND,kind); | |
values.put(Images.Thumbnails.IMAGE_ID,(int)id); | |
values.put(Images.Thumbnails.HEIGHT,thumb.getHeight()); | |
values.put(Images.Thumbnails.WIDTH,thumb.getWidth()); | |
Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values); | |
try { | |
OutputStream thumbOut = cr.openOutputStream(url); | |
thumb.compress(Bitmap.CompressFormat.JPEG, 100, thumbOut); | |
thumbOut.close(); | |
return thumb; | |
} catch (FileNotFoundException ex) { | |
return null; | |
} catch (IOException ex) { | |
return null; | |
} | |
} | |
} |
it works!! Thank u!
the image date added become Jan 1, 1970 when opened with Intent(Intent.ACTION_OPEN_DOCUMENT) anyone has this problem too?
Edit = Hmm... looks like it's a bug from my phone model, OnePlus One
For some reason the inserted image is very low quality, i tried replacing 50 with 100 in
source.compress(Bitmap.CompressFormat.JPEG, 50, imageOut);
but no change the image inserted in Pictures folder is very low quality
when I changing to PNG It's always saving as jpeg why ?
How to save image in new folder?
Per the api document of android, the timestamp should be refined as follow:
values.put(Images.Media.DATE_ADDED, System.currentTimeMillis() / 1000); // should be in unit of seconds
values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis()); // should be in unit of ms
Hello! I am new at Android and I am trying to use this Class to saVe a Bitmap frame from a video screenshot. Basically, I want to save a specific frame of a video from my phone Library. I am not sure why your code is not working. Probably is because ContentResolver. What is the correct way to passa this parameter at the function InsertImage?
I am showing my code here:
public class MainActivity extends AppCompatActivity {
private String videopath;
VideoView gravacao;
Button captura;
int currentPosition;
//TAG PARA LOG DE ERRO
String TAG = "LogErro";
//VARIÁVEIS GLOBAIS DO MEDIAMETADATA -> UTILZIADO PARA SALVAR FRAME DA VIDEOVIEW
MediaMetadataRetriever mediaMetadataRetriever;
Uri urivideosource;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gravacao = (VideoView) findViewById(R.id.videoID);
captura = (Button) findViewById(R.id.capturaID);
mediaMetadataRetriever = new MediaMetadataRetriever();
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("video/*");
startActivityForResult(intent, 1);
//mediaMetadataRetriever.setDataSource(videopath);
captura.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
currentPosition = gravacao.getCurrentPosition(); //in millisecond
Toast.makeText(MainActivity.this,
"Current Position: " + currentPosition + " (ms)",
Toast.LENGTH_LONG).show();
mediaMetadataRetriever.setDataSource(getApplicationContext(),urivideosource);
Bitmap bmFrame = mediaMetadataRetriever.getFrameAtTime(currentPosition * 1000); //unit in microsecond
//HERE IS WHERE I AM USING YOUR CLASS !!!!
CapturePhotoUtils capturePhotoUtils = new CapturePhotoUtils();
capturePhotoUtils.insertImage(getContentResolver(),bmFrame,"Meu Video","Descricao");
if(bmFrame == null){
Toast.makeText(MainActivity.this,
"bmFrame == null!",
Toast.LENGTH_LONG).show();
}else{
AlertDialog.Builder myCaptureDialog =
new AlertDialog.Builder(MainActivity.this);
ImageView capturedImageView = new ImageView(MainActivity.this);
capturedImageView.setImageBitmap(bmFrame);
ViewGroup.LayoutParams capturedImageViewLayoutParams =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
capturedImageView.setLayoutParams(capturedImageViewLayoutParams);
myCaptureDialog.setView(capturedImageView);
myCaptureDialog.show();
}
}});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == 1 && resultCode == Activity.RESULT_OK)
{
try
{
videopath = data.getData().toString();
//É NECESSÁRIO CRIAR URI PARA O MEDIAMETADATA FUNCIONAR. ELE NÃO VAI FUNCIONAR COM O PATHNAME!!
urivideosource = Uri.parse(videopath);
//URI CRIADO PARA O MEDIAMETADATA
gravacao.setVideoURI(Uri.parse(videopath));
MediaController mediaController = new MediaController(this);
gravacao.setMediaController(mediaController);
gravacao.start();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
}
hi
plz help
Uri url = cr.insert(Images.Thumbnails.EXTERNAL_CONTENT_URI, values); is Null
thx
while url null?