Uri vs File vs StringPath in android - android

Recently I am doing app deals with saving image and loading image on external storage. I am quite confused with Uri, File and StringPath.
For example, when load image from Gallery, it uses Uri.
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) { //Browse Gallery is requested
//Get the path for selected image in Gallery
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
//Access Gallery according to the path
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
loadImage(picturePath); //load picture according the path
image_View.setImageBitmap(pic); //Show the selected picture
}
Then when decode the image, it uses StringPath.
private void loadImage(String picturePath) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(picturePath,options);
int height_ = options.outHeight;
int width_ = options.outWidth;
float ratio = width_/height_;
int width = 480;
int height = 480;
if(width_>height_){
height = Math.round(width / ratio);
}else{
width = Math.round(width*ratio);
}
options.inSampleSize = calculateInSampleSize(options, width, height);
options.inJustDecodeBounds = false;
pic=BitmapFactory.decodeFile(picturePath,options);
}
Then when read byte from file, it uses File.
File cacheDir = getBaseContext().getCacheDir();
//Form a directory with a file named "pic"
File f = new File(cacheDir, "pic");
try {
//Prepare output stream that write byte to the directory
FileOutputStream out = new FileOutputStream(f);
//Save the picture to the directory
pic.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
So, what is the difference? Is it just different in usage but represent same directory?

Content URI looks something like:
content://media/external/images/media/53
The role of ContentResolver here is to get you an access to the image based on this URI, you don't need to know the filename or other properties of the file, you just need this URI to access the image.
String Path is the physical address of the image that stored which looks like:
file:///mnt/sdcard/myimage.jpg
and finally, File is the lowest handler which you need to operate with files. It uses the String Path as argument to create or open the file for read/write.
In your provided example here is the progress:
1- You ask ContentResolver to give you the real file path based on the provided URI
2- you load a bitmap file to a pic object based on the provided Path
3- you create a file named "pic" and compress the pic object to JPG and write to it

Related

Android BitmapFactory.decodeFile on jpeg file returns null

My app calls the camera to take a picture and save it into my app local directory (getApplicationContext().getFilesDir()) which works fine.
When I try to convert the picture into a bitmap using BitmapFactory the result is null. This the code I use :
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
String picturePath = pictureFile.getAbsolutePath();
Bitmap bitmap = BitmapFactory.decodeFile(picturePath, options);
Note that pictureFile was created as follows :
pictureFile = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
foodwarnDir /* directory */
);
Didn't you forget add permissions READ_EXTERNAL_STORAGE and/or WRITE_EXTERNAL_STORAGE ?
File locationOfFile = new
File(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/images");
File destination= new File(locationOfFile , fileName + ".JPG");
FileInputStream fileInputStream;
fileInputStream= new FileInputStream(destination);
Bitmap img = BitmapFactory.decodeStream(fileInputStream);
OR
This is my working code in my project here:
View imageHolder = LayoutInflater.from(this).inflate(R.layout.image_item, null);
ImageView thumbnail = (ImageView) imageHolder.findViewById(R.id.media_image);
try {
String path = uri.getPath();
Bitmap bmImg = BitmapFactory.decodeFile(path);
Point p = new Point();
p.set(100, 100);
Bitmap bitmapp = waterMark(bmImg, mRefNo, p, Color.RED, 90, 60, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapp.compress(Bitmap.CompressFormat.PNG, 100, stream);
Glide.with(this)
.load(stream.toByteArray())
.asBitmap()
.error(R.mipmap.ic_launcher)
.into(thumbnail);
mSelectedImagesContainer.addView(imageHolder);
thumbnail.setLayoutParams(new FrameLayout.LayoutParams(wdpx, htpx));
} catch (Exception e) {
e.printStackTrace();
}
Hope this helps you
other helpful Links1 Link2
Create temp file:
File tempFile = File.createTempFile("temp_file, ".jpg", this.getExternalCacheDir());
get path created:
String mPath = tempFile.getAbsolutePath();
now in you activityResult
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 8;
Bitmap bitmap = BitmapFactory.decodeFile(mPath, options);
use
data.getExtras().get("data");//for getting bitmap
Uri u = intent.getData();// for getting the Uri and get the path from uri
for getting data from your camera
Assuming you're using java.io.File class. According to Java docs function .createTempFile creates empty file on the System.
As such, this file will have only meta info without any content, with zero length, and this is probably a reason why it is not possible to extract Bitmap.
So you need to Create File Object instance instead of actual file, using new File()
You can also use WeakReference and similar to Bitmap you create if you're looking to decrease chance of memory leaks in early implementation.

Getting actual path from uri?

This is the code i used to get the uri of my image
Uri imageUri = data.getData();
How do I get the actual path of an image selected?
the Uri value/path that i am currently getting is
content://com.miui.gallery.open/raw/%2Fstorage%2Femulated%2F0%2FLightStick%2F144pixels.bmp
the correct filepath of the image that i need is for my other function is
/storage/emulated/0/LightStick/144pixels.bmp
The image selection function:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK){//everything processed successfully
if(requestCode == IMAGE_GALLERY_REQUEST){ //hearing back from image gallery
//the address of the image on the SD card
Uri imageUri = data.getData();
BMPfilepath =imageUri.getPath();
//stream to read image data from SD card
InputStream inputStream;
try {
inputStream = getContentResolver().openInputStream(imageUri);//getting an input stream, based no the URI of image
Bitmap image = BitmapFactory.decodeStream(inputStream);//get bitmap from stream
imgPicture.setImageBitmap(image);//show image to user in imageview
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(this, "Unable to open image", Toast.LENGTH_LONG).show(); //let user know image unavail
}//catch
} //requestCode == IMAGE_GALLERY_REQUEST
}
The upload function which uses the imageUri from the previous function.
String path = imageUri.getPath().toString(); the app crashes and goes to a looper file when in debug
public void onUploadToArduino(){
String path = imageUri.getPath().toString();//<- app crashes and goes to a looper file when in debug
String sdpath = System.getenv("EXTERNAL_STORAGE");
String extStore = Environment.getExternalStorageDirectory().getPath();
String FILENAME = extStore + "/LightStick/144pixels.bmp";
String collected = null;
FileInputStream fis = null;
FileInputStream fileInputStream = null;
byte[] bytesArray = null;
try {
File file = new File(FILENAME);//<- this works
//File file = new File(path);//<- this doesnt
bytesArray = new byte[(int) file.length()];
//read file into bytes[]
fileInputStream = new FileInputStream(file);
fileInputStream.read(bytesArray);
How do I get the actual path of an image selected?
You don't. A Uri is not a file and may not point to a file, let alone one that you can access.
Use a ContentResolver and openInputStream() to get an InputStream on the content identified by the Uri. Ideally, just use the stream. If you need a File for some other API that is poorly written and does not support streams:
Create a FileOutputStream on some File that you control (e.g., in getCacheDir())
Use the InputStream and the FileOutputStream to copy the bytes to your file
Use your file

How do i use this method in kitkat

I have tried many different ways or solutions and none of them seems to work. I have tried a few specific solutions which returns me a string and a context but i do not know what to do with the context even if I set the receiver of the context as null the app returns an error. What I want to do is, to be able to upload an image file for that I need the file path, a Uri or a content Uri gives me addresses like this
Content://something_something/304:
But i need something like this "
storage/sdcard/something_something/304.jpg"
how do it get that in KITKAT?
This is the code/method that I use for getting the path to the selected user Image.
public String getPath(Uri uri)
{
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
hope i provided enough details. Thank you for any help.
KITKAT does not provide the actual image path for security purpose.
if (Build.VERSION.SDK_INT >19){
InputStream imInputStream = getContentResolver().openInputStream(data.getData());
Bitmap bitmap = BitmapFactory.decodeStream(imInputStream);
String imagePath = saveGalaryImageOnKitkat(bitmap);
}
///After use you can delete the bitmap.
private String saveGalaryImageOnKitkat(Bitmap bitmap){
try{
File cacheDir;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
cacheDir=new File(Environment.getExternalStorageDirectory(),getResources().getString(R.string.app_name));
else
cacheDir=getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if(!cacheDir.exists())
cacheDir.mkdirs();
String filename=java.lang.System.currentTimeMillis()+".png";
File file = new File(cacheDir, filename);
file.createNewFile();
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
return file.getAbsolutePath();
}catch(Exception e){
e.printStackTrace();
}
return null;
}

Image Uri to File

I've got an Image Uri, retrieved using the following:
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
This works just amazing for Intents that require an Image URI, etc (so I know for sure the URI is valid).
But now I want to save this Image URI to a file on the SDCARD. This is more difficult because the URI does not really point at a file on the SDCARD or the app.
Will I have to create a bitmap from the URI first, and then save the Bitmap on the SDCARD or is there a quicker way (preferable one that does not require the conversion to a bitmap first).
(I've had a look at this answer, but it returns file not found - https://stackoverflow.com/a/13133974/1683141)
The problem is that the Uri you've been given by Images.Media.insertImage() isn't to an image file, per se. It is to a database entry in the Gallery. So what you need to do is read the data from that Uri and write it out to a new file in the external storage using this answer https://stackoverflow.com/a/8664605/772095
This doesn't require creating a Bitmap, just duplicating the data linked to the Uri into a new file.
You can get the data using an InputStream using code like:
InputStream in = getContentResolver().openInputStream(imgUri);
Update
This is completely untested code, but you should be able to do something like this:
Uri imgUri = getImageUri(this, bitmap); // I'll assume this is a Context and bitmap is a Bitmap
final int chunkSize = 1024; // We'll read in one kB at a time
byte[] imageData = new byte[chunkSize];
try {
InputStream in = getContentResolver().openInputStream(imgUri);
OutputStream out = new FileOutputStream(file); // I'm assuming you already have the File object for where you're writing to
int bytesRead;
while ((bytesRead = in.read(imageData)) > 0) {
out.write(Arrays.copyOfRange(imageData, 0, Math.max(0, bytesRead)));
}
} catch (Exception ex) {
Log.e("Something went wrong.", ex);
} finally {
in.close();
out.close();
}

How to speed up opening .png bitmaps on Android?

Welcome all
actually i'm opening png files from assets folder with this code:
public static Bitmap loadImage( String imageName ){
if( imageName.charAt(0) == '/' ) {
imageName = imageName.substring(1);
}
imageName = imageName + ".png";
Bitmap image = BitmapFactory.decodeStream(getResourceAsStream(imageName));
return image;
}
public static InputStream getResourceAsStream( String resourceName ) {
if( resourceName.charAt(0) == '/' ) {
resourceName = resourceName.substring(1);
}
InputStream is = null;
try {
is = context.getAssets().open( resourceName );
} catch (IOException e) {e.printStackTrace();}
return is;
}
This code opens the bitmaps with full cuality and it takes a lot of time to open it.
Also any sugerences to speed up the opening of the bitmap will be welcome
Thanks in advance
You can reduce the image size, setting how the image will be subsample on the moment it is loaded from file:
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inSampleSize= 2; // When 2, the orignal width will be divided by 2, and the height too.
Bitmap bmSource = BitmapFactory.decodeFile(path, opt);
If you need to load from a InputStream do that:
BitmapFactory.decodeStream(inputStream, null, opt);

Categories

Resources