I would like to use WebP format because it compresses (encodes) images very good (good quality and small size)
But on Android the next method to compress bitmap to WebP works quite slow
130-140 ms for bitmap with 640x360 resolution on device with Snapdragon 625
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.WEBP, 40, stream)
val webpBytes = stream.toByteArray()
Is there any faster method on Android to convert Bitmap or raw frame from camera (NV12) to compressed WebP image? Mb a third-party library?
I tried OpenCV and it works a little faster (100-107) but still it's not enough
MatOfInt params = new MatOfInt(Imgcodecs.IMWRITE_WEBP_QUALITY, 10);
MatOfByte matOfByte = new MatOfByte();
Imgcodecs.imencode(".webp", mat, matOfByte, params);
byte[] webpBytes = matOfByte.toArray();
Related
I'm trying to capture a YUV image but is stretched. I'm using Android Camera2 following this https://github.com/googlearchive/android-Camera2Basic. The Android SDK is 28.
I'm facing a weird behavior when I capture a camera frame in YUV 2048x1536 from the method setOnImageAvailableListener() using the ImageReader. The capture is stretched:
YUV 2048x1536 stretched
What I do:
pictureImageReader.setOnImageAvailableListener(
reader -> {
Image image = reader.acquireLatestImage();
if(image != null){
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
image.close();
}
}, mBackgroundHandler);
To convert image to bitmap I used this How to convert android.media.Image to bitmap object?:
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
However if I change the resolution my capture is fine (YUV 960x720):
YUV 960x720 ok
I don’t know why the capture in YUV 2048x1536 is stretched and in YUV 960x720 isn’t it. The only change is the resolution
Thanks
Does the device actually list 2048x1536 as a supported size in its stream configuration map? Sometimes camera devices will accept a resolution they don't actually list, but then can't properly output it.
If that size is listed, then this may just be a bug on that device's camera implementation, unfortunately.
(Also, it looks like you're capturing JPEG images, not uncompressed YUV, not that it necessarily matters here).
I am now a newbie to android programming.
I am very confused when processing with images.
I am now trying to load a jpeg image to bitmap and then convert bitmap to byte array and vice versa.
I am testing with the first case: load jpeg to bitmap and get byte array.
My input image 520 x 390 (24 bit color) 24KB JPEG.
My output byte array is ~ 290000 bytes ~ 290KB, very large from the original one.
How can I convert it into byte array with the same size or nearly the same size as the original JPEG?
Therefore, I wonder if the inverse conversion will convert byte array to jpeg the same size or not ?
Here is my code:
Resources r = this.getResources();
Bitmap bm = BitmapFactory.decodeResource(r,R.drawable.plot);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG,100,baos);
byte[] byteArray = baos.toByteArray();
bitmap.compress has a property of quality (the 2nd one). try reducing if from 100 to a lower number (0-100).
The JPEG you loaded is most likely to have a level of compression, which is what makes JPEGs smaller, by trading quality for size.
In your code you are setting a compression level of 100, this means no compression at all, so the bitmap is saved in JPEG format, but as it is without any size/quality reduction at all.
If you change the compression level to anything lower than 100 you will see how the file size gets smaller. Try between 80 to 90 to keep a good quality while getting a smaller file.
How can I convert it into byte array with the same size or nearly the same size as the original JPEG?
Just load the jpg file in a byte array if you need it in a byte array.
There is no need to convert to bitmap first.
I was struggeling to get YuvImage to a png imageformat on an Android 5.0.1 device where the png showed up as green images. On a Android 5.1.1 this did not happend, and the images was showing just fine.
After some time I found out that there is a bug in Android 5.0.1 which makes the images that are converted appear green. This was fixed in Android 5.1.1
However, does anyone know about a solution in order to make this work on devices that has not got this fix?
I don't think there is a way to workaround the bug because in my experience the images are already green when generated by the system, and it is not a problem of the conversion to PNG.
I see that you are using the Camera 2 API from your comment response, and since you are using YUV format I believe you are trying to save images from the continuous feed from the camera (as opposed from full resolution picture taking). If that is the case, I'll suggest using the older Camera API if at all possible, as I haven't seen a device that does not work when capturing preview images in YUV format (NV21), which can easily converted to a PNG, although having to go through a JPEG step:
YuvImage yuvImage = new YuvImage(nv21bytearray, ImageFormat.NV21, width, height, null);
ByteArrayOutputStream os = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, os);
byte[] jpegByteArray = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory() + "/imagename.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
with nv21bytearray being the NV21 byte array returned by the old camera API onPreviewFrame(...) method.
I am developing an app which generate .png images from a 1080p video. But the pngs are in MBs, and even my app is crashing due to large size of pngs. I want to compress or something like that to reduce the size of each png. I have done a lot of methods like createScaledBitmap, or compress(CompressFormat.PNG, 20, stream); or Bitmap.createBitmap(source, 0, 0, source.getWidth(),source.getHeight(), m, true); also searched a lot of methods.
But it's not reducing the size as much as I want. it still remains in 2.2+ MB per png.
Any idea other than these. Thanks.
I am also building an app which deals with high resolution images but on server side. I am compressing and re-sizing the image on server side by using thumbnailator-0.4.8.jar. Example
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage bImageFromConvert = ImageIO.read( in );
BufferedImage newImage = Thumbnails.of(bImageFromConvert).size(213, 316).asBufferedImage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(newImage, "jpg", baos);
baos.flush();
retVal = baos.toByteArray();
baos.close();
I am trying to compress the photo took by the camera in Android. But the color of the image changed when it compressed by Bitmap.CompressFormat.JPEG. How can I solve this problem? Thanks
I have put some sample images which generated from my code. You can see the color of the paper on the top of the images is different.
Here is the code snippet:
Bitmap bitmap = BitmapFactory.decodeFile(Common.FOLDER_PATH + "pic.jpg");
FileOutputStream stream2 = new FileOutputStream(Common.FOLDER_PATH + "pic100.jpg");
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream2);
FileOutputStream stream3 = new FileOutputStream(Common.FOLDER_PATH + "pic100.png");
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream3);
This is original image:
This is JPEG:
This is PNG:
JPEG is a lossy compression format and there may be loss of image information during the compression. The sacrifice of original image information is made for a better compression ratio (resulting in smaller file).
However, if this is not acceptable for you, you should use one of the lossless compression methods which includes the PNG.