I am writing an Android app which can take pictures and save them on the SD card. Later, I need to display the pictures in a GridView and the user can select one. This is my code to save pictures:
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera c) {
currentPictureName = (String) getResources().getText(R.string.username)
+ System.currentTimeMillis() + ".jpg";
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(sdcardPath + currentPictureName);
outStream.write(data);
outStream.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
mCamera.startPreview();
}
}
However, none of the saved images have thumbnails to show in the GridView. How do I automatically generate thumbnails for all images that I save and add everything to MediaStore so that they can be accessed later?
Try using scanFile() function.
You must implement a media scanner connection client
private class ImageScannerClient implements MediaScannerConnection.MediaScannerConnectionClient {
#Override
public void onMediaScannerConnected() {
// Start scanning files you have in a que
}
#Override
public void onScanCompleted(String path, Uri uri) {
// Run some code, then maybe initiate scan of next file in que
}
}
In onCreate you can connect to the media scanner like so:
// Connect to media scanner
this.mediaScanner = new MediaScannerConnection(getApplicationContext(), new ImageScannerClient() );
this.mediaScanner.connect();
And at some other point you must add files to a que or something to be scanned.
Found this. This works perfectly fine, all thumbnails are automatically generated
Related
I am trying to make an app which downloads the pdf file from the internet and saves it to Downloads folder. After downloading the pdf,instead of opening a 3rd party pdf app , I want it to render in the app itself.( I have done downloading and saving in Downloads folder part). For this, I have to use PDFRendered. But the problem I am facing is that I am a newbie and after looking at some tutorials , I am able to render a pdf properly but only when it is present in the assets folder. Downloaded pdf is present in the Downloads folder. Is there any way in which I can use the pdf from Downloads folder and render it in the app itself instead of pre-defining the pdf file in the assets folder?
I have tried downloading and saving file in Downloading folder and I have successfully done it but I'm unable to use the file to render as it is not inside assets folder.
//Code which is successfully rendering pdf from assets folder. How to
//use it to render pdf from Download folder?
public class PdfRender extends AppCompatActivity {
#BindView(R.id.pdf_image) ImageView imageViewPdf;
#BindView(R.id.button_pre_doc) FloatingActionButton prePageButton;
#BindView(R.id.button_next_doc) FloatingActionButton nextPageButton;
private static final String FILENAME = Environment.DIRECTORY_DOWNLOADS+"/a.pdf";
private int pageIndex;
private PdfRenderer pdfRenderer;
private PdfRenderer.Page currentPage;
private ParcelFileDescriptor parcelFileDescriptor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pdf_render);
ButterKnife.bind(this);
pageIndex = 0;
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
protected void onStart() {
super.onStart();
try {
openRenderer(getApplicationContext());
showPage(pageIndex);
} catch (IOException e) {
e.printStackTrace();
}
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void onStop() {
try {
closeRenderer();
} catch (IOException e) {
e.printStackTrace();
}
super.onStop();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#OnClick(R.id.button_pre_doc)
public void onPreviousDocClick(){
showPage(currentPage.getIndex() - 1);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#OnClick(R.id.button_next_doc)
public void onNextDocClick(){
showPage(currentPage.getIndex() + 1);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void openRenderer(Context context) throws IOException {
// In this sample, we read a PDF from the assets directory.
File file = new File(context.getCacheDir(), FILENAME);
if (!file.exists()) {
// Since PdfRenderer cannot handle the compressed asset file directly, we copy it into
// the cache directory.
InputStream asset = context.getAssets().open(FILENAME);
FileOutputStream output = new FileOutputStream(file);
final byte[] buffer = new byte[1024];
int size;
while ((size = asset.read(buffer)) != -1) {
output.write(buffer, 0, size);
}
asset.close();
output.close();
}
parcelFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
// This is the PdfRenderer we use to render the PDF.
if (parcelFileDescriptor != null) {
pdfRenderer = new PdfRenderer(parcelFileDescriptor);
}
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void closeRenderer() throws IOException {
if (null != currentPage) {
currentPage.close();
}
pdfRenderer.close();
parcelFileDescriptor.close();
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void showPage(int index) {
if (pdfRenderer.getPageCount() <= index) {
return;
}
// Make sure to close the current page before opening another one.
if (null != currentPage) {
currentPage.close();
}
// Use `openPage` to open a specific page in PDF.
currentPage = pdfRenderer.openPage(index);
// Important: the destination bitmap must be ARGB (not RGB).
Bitmap bitmap = Bitmap.createBitmap(currentPage.getWidth(), currentPage.getHeight(),
Bitmap.Config.ARGB_8888);
// Here, we render the page onto the Bitmap.
// To render a portion of the page, use the second and third parameter. Pass nulls to get
// the default result.
// Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
currentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
// We are ready to show the Bitmap to user.
imageViewPdf.setImageBitmap(bitmap);
updateUi();
}
/**
* Updates the state of 2 control buttons in response to the current page index.
*/
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void updateUi() {
int index = currentPage.getIndex();
int pageCount = pdfRenderer.getPageCount();
prePageButton.setEnabled(0 != index);
nextPageButton.setEnabled(index + 1 < pageCount);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public int getPageCount() {
return pdfRenderer.getPageCount();
}
}
Update-: I tried to make changes to a working code of Rendering app and edit openRenderer() to make changes and give my file name and location as below but still the pdf file dosen't open even thugh it is detected (checked in logs using file.exists()) . Any way to find solution to this problem?
`private void openRenderer(Context context) throws IOException {
File file = new File("storage/emulated/0/Download/" + FILENAME);
if (!file.exists()) {
Log.e("testit", "Not exists");
FileInputStream asset = new FileInputStream(file);
FileOutputStream output = new FileOutputStream(file);
final byte[] buffer = new byte[1024];
int size;
while ((size = asset.read(buffer)) != -1) {
output.write(buffer, 0, size);
}
asset.close();
output.close();
}
parcelFileDescriptor = ParcelFileDescriptor.open(file,ParcelFileDescriptor.MODE_READ_ONLY);
// This is the PdfRenderer we use to render the PDF.
if (parcelFileDescriptor != null) {
pdfRenderer = new PdfRenderer(parcelFileDescriptor);
}
}`
I get the following error in logs
`java.lang.NullPointerException: Attempt to invoke virtual method 'void android.graphics.pdf.PdfRenderer.close()' on a null object reference`
Expected results are fetch and download the pdf from the internet. Click on a button which downloads and immediately after downloading renders the pdf in the app itself and users can view the pdf in the app itself without the use of any 3rd party pdf app or a webview(for users after or on 5.0).
I'm having a problem with android's camera2 API.
My end goal here is to have a byte array which I can edit using opencv, whilst displaying the preview to the user (e.g. an OCR with a preview).
I've create a capture request and added an ImageReader as a target. Then on the OnImageAvailableListener, i'm getting the image, transforming it to a bitmap and then display it on an ImageView (and rotating it).
My problem is that after a few seconds, the preview stalls (after gradually slowing down) and in the log om getting the following error: E/BufferItemConsumer: [ImageReader-1225x1057f100m2-18869-0] Failed to release buffer: Unknown error -1 (1)
As you can see in my code, I have already tried closing the img after getting my byte[] from it.
I've also tried clearing the buffer.
I've tried closing the ImageReader but that of course stopped me from getting any further images (throws an exception).
Can anyone please help me understand what im doing wrong? I've been scouring google to no avail.
This is my OnImageAvailableListener, do let me know if you need more of my code to assist:
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image img = reader.acquireLatestImage();
final ImageView iv = findViewById(R.id.camPrev);
try{
if (img==null) throw new NullPointerException("null img");
ByteBuffer buffer = img.getPlanes()[0].getBuffer();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
final Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length);
runOnUiThread(new Runnable() {
#Override
public void run() {
iv.setImageBitmap(b);
iv.setRotation(90);
}
});
} catch (NullPointerException ex){
showToast("img is null");
}finally {
if(img!=null)
img.close();
}
}
};
Edit - adding cameraStateCallback
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
showToast("Connected to camera!");
createCameraPreviewSession();
}
#Override
public void onDisconnected(CameraDevice cameraDevice) {
closeCamera();
}
#Override
public void onError(CameraDevice cameraDevice, int i) {
closeCamera();
}
};
private void closeCamera() {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
You seem to have used setRepeatingRequest() for Jpeg format. This may not be fully supported on your device, also depends on the image resolution that you choose. Normally, we use createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) in these cases, and get YUV or raw format from ImageReader.
I would try to choose low resolution for Jpeg: maybe this will be enough to keep the ImageReader running.
So, I'm (still) trying to build a simple camera app and what I have so far is an Image Controller which is able to take a picture, save it into the storage and pass the filepath with an intent to another activity.
In my new activity the first step I'm tying to achieve is, to get my final Image loaded into an ImageView, so I did the following:
ImageView finalImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_after);
Intent getIntent = getIntent();
String filePath = getIntent.getExtras().getString("filePath");
File imgFile = new File(filePath);
if(imgFile.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
finalImage = (ImageView) findViewById(R.id.finalImage);
finalImage.setImageBitmap(myBitmap);
}
But, its not working, and I dont quite unterstand why not... :( The Activity starts completely fine, but the ImageView just does nothing.
There are few things you must know in the process of saving Image in Android
ccv2WithPreview.takePicture();
In this line the method executed is
public void takePicture() {
try {
// This is how to tell the camera to lock focus.
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
// Tell #mCaptureCallback to wait for the lock.
mState = STATE_WAITING_LOCK;
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Toast.makeText(activity.getApplicationContext(), file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
}
In this method, capture() call is asynchronous. Since you are ending the activity soon after calling it and starting new Activity, so by the time your code saves the Image in Image Saver, you are starting new Activity already and your file is not yet ready.
You button implementation works because by the time you click button, Image will be saved.
To solve this problem,
CameraHelper.java
public interface CameraHelper{
void fileSaved(String filePath);
}
MainActivity.java
public class MainActivity extends AppCompatActivity
implements SensorEventListener, ActivityCompat.OnRequestPermissionsResultCallback, CameraHelper{
...
#Override
public void fileSaved(String file){
Intent intent = new Intent(this, AfterActivity.class);
intent.putExtra("filePath", file);
startActivity(intent);
finish();
}
}
in onCreate of MainActivity
ccv2WithPreview = new CameraControllerV2WithPreview(MainActivity.this, textureView, MainActivity.this);
in your camera class
private CameraHelper cameraHelper; //Initialize in constructor
Then in ImageSaver
private boolean imageSaved = false;
public void run() {
if(!imageSaved) {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
try (FileOutputStream output = new FileOutputStream(mFile)) {
output.write(bytes);
imageSaved = true;
cameraHelper.fileSaved(mFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
}
}
}
This is how you must handle any Asynchronous tasks you get in future. Callback based implementations.
Can you try to invalidate() the ImageView after setting the bitmap?
(I'm pretty much guessing here, but working with GUIs a couple of years ago, i remember that if a view changed you have to tell the view to about it, so that it can be redrawn.)
Please also see: How to refresh image view immediately
I have an Android application that loading some information and one picture like a blog, but sometimes I got duplicates picture, I don't know what is the problem, but sometimes it works good.
Someone here can help me ?
Here's the code below:
"endereco" is the URL of picture and "view" is the context that I pass on the class that extends activity"
public void loadImg(final View view , final String endereco){
Thread nova = new Thread()
{
public void run() {
Bitmap img = null;
try
{
URL url = new URL(endereco);
HttpURLConnection conexao = (HttpURLConnection) url.openConnection();
InputStream input = conexao.getInputStream();
img = BitmapFactory.decodeStream(input);
Log.i("Funcionou","Foto: " + endereco);
} catch (Exception ex){
Log.i("Erro",ex.toString());
}
final Bitmap imgAux = img;
handler.post(new Runnable() {
#Override
public void run() {
ImageView imageView = (ImageView) view.findViewById(R.id.txtfoto);
imageView.setImageBitmap(imgAux);
}
});
}
};
nova.start();
nova.currentThread().interrupt();
}
If you are downloading an image from a wbepage or server i wouldnt do it in a thread give it its own AsyncTask it gives you a whole load of methods that allow you to better control over what you are downloading and what to do with it after it has been downloaded.
Check out the Android dev Docs http://developer.android.com/reference/android/os/AsyncTask.html
I am pretty new to Android development and I'm trying to figure out how to tap an image in my app and save it to the device. When the image is tapped I want a Save button to appear and when that is pressed, a toast should appear saying the picture was saved. On iOS I am able to do this with UIActionSheet.
I should also mention that the image view image is downloaded from a URL using Picasso.
I just tried this and it says the image saved but when I go to the photos app on my phone, the image is not there.
largeImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
saveButton.setVisibility(View.VISIBLE);
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
largeImage.getDrawable();
Bitmap bitmap = ((BitmapDrawable)largeImage.getDrawable()).getBitmap();
OutputStream outStream = null;
File file = new File(storageDirectory, "er.PNG");
try {
outStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
outStream.flush();
outStream.close();
Toast.makeText(FlickrImageActivity.this, "Saved", Toast.LENGTH_LONG).show();
}
catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(FlickrImageActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
catch (IOException e) {
e.printStackTrace();
Toast.makeText(FlickrImageActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
saveButton.setVisibility(View.GONE);
}
});
String root = Environment.getExternalStorageDirectory().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 file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
Manifest permission
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
You can use RelativeLayout to contain a ImageView and a Button.
Align both of them center in parent
inside the activity, set the button visibility to "gone"
call setOnClickListener of the ImageView and Button to your Activity
implement OnClickListener in your Activity
inside onClick(View v), if the view clicked is the ImageView, set the visibility of Button to "visible"
inside onClick(View v), if the view clicked is the Button, save the image to disk
** how to save image to disk
if the image source is drawable resources, use BitmapFactory.decodeResource to create a Bitmap then use Bitmap.compress to export to a specific path
specific path is recommended to be obtained from Environment.getExternalStoragePublicDirectory
then notify the Android to refresh gallery
MediaScannerConnection.scanFile(context,
new String[] { imagePath }, null,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
//....
}
});
Then use a Toast.makeText(context, "message here").show(); to show the message to user
See below steps to acheive this in Android :
1. Create layout with ImageView & 'Save' named Button
2.By deafult set 'Save' Button's visibility = gone/invisible
3. Apply click listener on both the views (ImageView & Button)
4. OnClick of ImageView, set 'Save' Button's visibility = visible
5. onclick of save button click call your save image to sdcard logic. Check below link for that.
http://android-er.blogspot.in/2010/07/save-file-to-sd-card.html
Hope this will help you.