How to handle high resolution image? - java

I have a profile page and I also have profil image that is to be downloaded from server and then put in image view. Every time I open profil page this process repeats itself. When image is below 500 kb or around, everything is okay but when I put 6mb image on it, the page is not smoothly working. I mean when scrolling or doing anything everything takes time. It is like running high graphic game on weak computer. After undergoing this process, I tried to compress image and was able to reduce the size to 2 MB by this library https://github.com/zetbaitsu/Compressor. Nothing less. Why does this problem occurs.
I am doing this upload process on Async task.
Upload method
public void upload() {
if (filePath != null) {
Bitmap compressedImage = null;
try {
compressedImage = new Compressor(context).compressToBitmap(new File(filePath.getPath()));
} catch (IOException e) {
e.printStackTrace();
try {
compressedImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), filePath);
} catch (IOException e1) {
e1.printStackTrace();
}
}
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
compressedImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
final String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), compressedImage, "Title", null);
StorageReference sRef = storageReference.child("images/" + name);
sRef.putFile(Uri.parse(path))
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
if (ımageView != null)
ımageView.setImageURI(Uri.parse(filePath.getPath()));
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Log.i("resultUpload", exception.getLocalizedMessage());
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
}
});
} else {
}
}
My download image method
public void download(final ImageView ımageView) {
StorageReference sRef = storageReference.child("images/" + name);
sRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.get().load(uri).into(ımageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i("resultDownload", e.getLocalizedMessage());
}
});
}

What you can do, as Milan said, is to get the image from a URL online and then set that image to your imageView. First, you will have to make sure that you have internet permission with :
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Then you can do the following to set an image into the imageView:
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL("Your image URL comes here".getContent());
imageView.setImageBitmap(bitmap);
This should work by getting a bitmap of the image located at the URL that you have specified. It will then set the imageView to that bitmap.
OR, what you can do is use Picasso. Add this to your app/build.gradle:
implementation 'com.squareup.picasso:picasso:2.5.2'
Then use this Java code to set the image into the imageView:
String imageUri = "Your image URL";
Picasso.with(getApplicationContext()).load(imageUri).into(imageView);
This uses Picasso to get the image from the URL into the imageView.
I hoped this helped.

This is not a Java problem. Irrespective of language or platform you need to do certain things to properly display an image on the web. So, instead of recommending any Java library (I'm sure you'll get many open source libraries in every language), I'm going to enumerate the basic steps you need to follow:
You need to resize (not cropping) the image for multiple devices. No decent website downloads 6MB image. Never! Not even 2MB image. My Facebook profile image, which I captured on my 8MP mobile camera, is 160 KB in size after uploading. Try to bring down the image size to around 100 - 150 KB. These are some usual image dimensions.
You'd create resized image for mobile, tablet and laptop. For mobile, it's usually 640 x 480. For tablet, it's usually 800 x 600. For Laptop, it's usually, 1024 x 768
Then compress the image as you did. Make sure that the final image is progressive jpeg/jpg. Progressive jpeg is compressed in layers. The browsers that support progressive images display a hazy preview when the image is being downloaded. This improves user experience. For the browsers that do not support progressive image, some work-arounds are used. For e.g. you can create a low quality version of your image (approx. 1KB in size) with opacity: 1; filter: blur(20px);. Thus a blurred version of the image will be displayed as the higher quality image is being downloaded. Initially you set the opacity of the higher quality image to 0. Once the higher quality image download is complete, you set the opacity of the lower-quality image to 0 and the higher-quality image to 1. You can test whether your image is progressive or not here and can create compressed progressive image here. You'd probably do these things programmatically, but these resources may serve as a reference.
Ensure that your server supports HTTP/2 which is fully multiplexed. You can see the multiplexing here. Thus the resources can get downloaded parallely.
Ensure your server supports gzip or compression. Thus the resources are transferred over the network in gzipped format and extracted automatically by the browser. This ensures fast download.
Use proper cache-control headers, so that the browser caches the images eliminating the need to download the image for every visit.
If possible a mobile first design should be used, so that for mobile the performance gets better.

Related

Can I reduce the size of the image I bring from firebase?

There is a problem that the image is not visible when the image is imported from the Firebase Storage and put into the ImageView.
In my opinion, the reason is that the size of the image is large.
When I import the image I am keeping, I think I need to reduce the size of the image. Is there a solution?
This is my code.
part.orderByChild("Art_ID").equalTo(art_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot asnap : snapshot.getChildren()) {
Log.i("ValueArtinfo", asnap.getValue().toString());
String art_filename = asnap.child("Filename").getValue(String.class);
StorageReference sart = storage.getReferenceFromUrl("gs://myaddressxxx.com/Art/" + art_filename + ".jpg");
// Bitmap bm = BitmapFactory.decodeFile(String.valueOf(sart));
// Bitmap bm = ShrinkBitmap(sart, 300, 300);
Glide.with(getApplicationContext()).load(sart).into(str_art);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
And this is my firebase storage. As you can see, the file size is large and the number is about 1,000.
I tried the following solution but failed.
http://android-coding.blogspot.com/2011/06/reduce-bitmap-size-using.html
Yes, having a 7 Mb image, can be considered a large size image. As also #GokulNathKP mentioned in his answer, you can display a thumbnail while the bigger image is loaded, but that will not solve the issue related to the size of the image.
So the best option that you have is to upload the images in smaller sizes from the beginning. You can resize them using different libraries so you can have stored in the end an image of a decent size. In that way, you can have faster downloads and lower bills to pay.
Maybe you can just try to load the thumbnail, until the actual image is loaded in background, using Glide.
A sample code:
Glide.with(context).load("actual-url")
.placeholder(R.drawable.placeholder)
.thumbnail(0.3f) //Quality 0.1 - 1.0
.into(imageHolder);

Android Camera App using CameraX to save images in YUV_420_888 format

I want to save image stream (preferably 30fps) to the device. I came across this post.
How do I dump images in YUV_420_888 format using cameraX without encoding it in JPEG?
Also, I'll be glad if any one can suggest any direction in saving burst of images.
Till now I'm only saving an image by onclick of button
findViewById(R.id.capture_button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"Image_" + System.currentTimeMillis() + ".jpg");
imageCapture.takePicture(file, new ImageCapture.OnImageSavedListener() {
#Override
public void onImageSaved(#NonNull File file) {
Toast.makeText(CameraCaptureActivity.this, "Photo saved as " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
}
#Override
public void onError(#NonNull ImageCapture.ImageCaptureError imageCaptureError, #NonNull String message, #Nullable Throwable cause) {
Toast.makeText(CameraCaptureActivity.this, "Couldn't save photo: " + message, Toast.LENGTH_SHORT).show();
if (cause != null)
cause.printStackTrace();
}
});
}
});
How do I dump images in YUV_420_888 format using cameraX without
encoding it as JPEG?
You can use another version of ImageCapture.takePicture() that returns an im-memory image in YUV_420_888 format, ImageCapture.takePicture(Executor, OnImageCaptureCallback).
imageCapture.takePicture(executor, new ImageCapture.OnImageCapturedCallback() {
#Override
public void onCaptureSuccess (ImageProxy imageProxy) {
// Use the image, then make sure to close it before returning from the method
imageProxy.close()
}
#Override
public void onError (ImageCaptureException exception) {
// Handle the exception however you'd like
}
})
I'll be glad I could any direction in saving burst of images.
Burst images are images taken one after another at a certain rate. How you implement it in your app depends on what you want the user experience to look like, it can be triggered from a single button click or a long click. The main thing is you'll have to make a number of calls to ImageCapture.takePicture(), you can control the image capture rate using APIs such as Handler.postDelayed(Runnable, Long).

save to a Drawable from Piccaso

I'm making an app that in many other functions, pulls images via URL and then it shows them in a PDF file. I did it on the hard way downloading them and using an asyncTask to handle all the process, but I heard that piccasso does this work better and cleaner so I decided to give it a try.
So I want to put the image loaded with piccaso within a Drawable so let's say I'm trying to do something like this:
Drawable drawable=Picasso.get().load("URL");
which of course is ridiculous and it's impossible, so I'm wondering if there is a way I can pull the image
with picasso and then transform it to a Drawable so I can then draw it on the PDF file that I need to generate
This code may help you:
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
imageView.setImageBitmap(bitmap);
Drawable image = imageView.getDrawable();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {}
};
Picasso.with(this).load("url").into(target);
Or, just look here: https://stackoverflow.com/a/25799983/11162243

Picasso Image Caching with Recyclerview

I am using picasso inside my recyclerview adapter for loading images from network. I've tested it with 40+ items in my recyclerview and 29 of them have images.
I noticed that upon reaching the end of list, when I scroll back up, some of the images are being reloaded from network instead of cache. Is there any way to prevent reloading the image again from the network? Or perhaps an alternative for reducing network bandwidth usage.
Picasso.with(context)
.load(HOST + post.getImage_url())
.resize(1920, 1080)
.onlyScaleDown()
.networkPolicy(NetworkPolicy.OFFLINE)
.into(holder.ivPostImage, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(context)
.load(HOST + post.getImage_url())
.resize(1920, 1080)
.onlyScaleDown()
.into(holder.ivPostImage);
}
});
Above is the code that I use for caching images loaded from the network.

Getting image data continuously from camera, SurfaceView or SurfaceHolder

So I have this camera preview set up with Camera, SurfaceView and SurfaceHolder.
I have also an ImageView where I will be putting a modified version of the camera image and I want this to update lets say once every second.
All code is ready and already working when I load images from "res" but I have a really hard time reading the image data from the camera.
I've tried following already:
Creating an intent for MediaStore.ACTION_IMAGE_CAPTURE and starting an onActivityResult getting a small thumbnail (enough for me actually) from (Bitmap)data.getExtras().get("data")
The problem is that this opens the camera App and you need to "manually" take a picture.
Creating a Camera.PreviewCallback, taking the YuvImage, and converting it to an image using YuvImage.compressToJpeg(...).
The problem here is that I can't get it to start no matter when or where i put the Camera.setPreviewCallbackWithBuffer(PreviewCallback).
Try to take the data directly from PreviewHolder by locking in to the canvas using lockCanvas() and trying to convert it to a bitmap
Obviously Doesn't work.
Edit:
What is the best way to make this work? I mean QR-Code readers must read the image data out of the camera continuously, how do they work?
I went for option number 2 and finally made it work.
used this callback, forgot the #Override before
private Camera.PreviewCallback previewCallback= new Camera.PreviewCallback()
{
#Override
public void onPreviewFrame(byte[] data,Camera cam)
{
Camera.Size previewSize = cam.getParameters().getPreviewSize();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21,previewSize.width,previewSize.height, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0,0,previewSize.width,previewSize.height),80,baos);
byte[] jdata = baos.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jdata,0,jdata.length);
}
};
And initiating it using setPreviewCallback rather than setPreviewCallbackWithBuffer
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback()
{
public void surfaceCreated(SurfaceHolder holder) {
camera.setPreviewCallback(previewCallback);
}
}

Categories