Screenshot compression loss of quality - android

Maybe someone else was faced with this problem:
As the title says, when uploading screenshots from devices to our server image quality degradation is quite high. You can see one example on the following link
http://cdn.voicebo.com/7507-05e6a7b3bf91d96b2d08da649c2ef590.jpg
This screenshot was taken on Nexus 4 but same thing happens on Galaxy S2, S3 and Note 2. Unfortunately we don't have more phones to test for this right now but considering popularity of following models this affect large number of our users.
I have searched for quite some time to answers or reasons why this might happen and found the following link which is not really what I was looking for but contains some information
http://www.google.rs/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CCYQFjAA&url=http%3A%2F%2Fandroidforums.com%2Fsamsung-galaxy-s3%2F580114-screenshot-glitch.html&ei=1dKdUbPNA8nBO7G9gPgE&usg=AFQjCNECq7UNMp16pU8WLMlLwZVb4i2Ofw
I have also came to conclusion that screenshot images are saved as png files while images from the camera are in jpeg (I think this is same for all ROMS but might be wrong) so this might be the problem too. Part I don't get is why would this be an issue, because as I understand when you read image file from any supported format you get raw bytes of data for that image so input format shouldn't play role in output compression if raw bytes were read without errors.
Relevant part of code in image compression is only this but if more info is required I can add more:
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos);
Questions I am asking are:
Has anyone else faced this problem and how did you solve it?
How should I compress png images (using what settings) to get best results at reasonable file size?
Bonus:I am currently trying out a way to detect which file format the image is but if someone used this to solve similar issue please mention that in answer too.
Edit:How to get the Image Format of the images from Gallery is the part I am using now to get format of image but this doesn't actually answer the question. Thanks to all the guys there for useful discussion.

Now you've mentioned the options.inSampleSize setting, it seems incredibly likely that your problem is caused by this: setting options.inSampleSize = 4 tells the encoder to throw pixels away (apparently literally; proper resampling would look better than your example), which is exactly what you're seeing.
You need to make some decisions about what should be reduced in size and what shouldn't - you say in your comment than this setting should be determined by input bounds, so it sounds like you're already doing this and perhaps you need some debugging there.
I'd reiterate that changing PNGs to JPEGs might not be the best option, unless your screenshots often contain photographic content. As you may know, PNG is very poor at compressing photographic content, but conversely, JPEG is very poor at maintaining quality with the sorts of images commonly found on computer / device screens. PNG can often produce smaller files in such circumstances than acceptable JPEG images.

Related

Fresco : A question on Inner workings when using data uri for loading images/animations (webp/gif)

So, we are using Fresco in our android app and so far it has been great. There is one issue that we are seeing when we load an image of size 8000x4500. We are seeing a Jank when that image is being loaded in the list on all devices and on some lower end devices, we are getting an OOM error (which is ok because we were testing on a 80$ device which is low on resources). Not sure if we are doing anything wrong or missing something.
In our app all images are encoded as DataUris (conforms to RFC 2397) and we are loading the images using setImageURI method.
Now my question is, does the conversion of URI to bitmap inside Fresco happens on the same thread or does it happen in a background thread? I was trying to browse the code and understand it myself, but understanding the control flow wasn't straightforward. In particular, I couldn't figure out how the mTopLevelDrawable is updated for ImageRequest of type DataUri.
Any help on understanding how it works, what could be done at the application level to prevent it would be great.
We are ok to set a maximum dimension to something like 1280 or the width of the window. Would that help reduce the decoding time?
Thanks in advance!
Note : We deliberately choose a high resolution image to understand the limits of our product. For regular sized images, things are pretty smooth. For high resolution images, even on higher end devices like pixel 4, there is a jank.

Compress image without losing the quality

I've been developing an Android app which takes picture and save it. And I want make the upload speed more faster by compressing the image. But as I compressed them using BitmapCompress, the image seems lost its quality. Here :
RAW :
COMPRESSED :
BEFORE :
DIMENSION - 1920X1920
FILE SIZE - 2.94MB
AFTER :
DIMENSION - 960X960
FILE SIZE - 644KB
I wonder if there's a way, a library perhaps that will solve my problem? Instagram seems to be doing this compression stuff without losing the image quality.
Compressing will always lead to decreased quality in the one or the other way.
Here is what you could do:
Change your compression format to PNG, if you are not already using that.
Find a perfect compromise for the quality value between size and quality
I agree with #Saret BitmapCompress will decrease the file size with a good quality. You can get ~800-900KB photo from ~3MB photo using 80% quality compressing without scaling. You can get better result if you crop the photo.
If you don't care scaling and details in depth are not important for you, I strongly recommend following libraries:
https://github.com/shaohui10086/AdvancedLuban
https://github.com/zetbaitsu/Compressor
Bitmap yourbitmap
[...]
OutputStream os = new FileOutputStream(filename);
yourbitmap.compress(CompressFormat.JPEG, 80, os); // 80% compression
This will keep your image light and with a good quality.
Some keywords worth looking into:
'EXIF removal' libraries
'lossless compression' libraries
Explanations:
Remove some of the excess EXIF data
You can try reducing filesize by removing the EXIF data that is stored in the image. In many cases, the EXIF data takes up a lot of room, and often contains more information than the user might need for their use case.
A quick google search shows the following tool could be helpful in removing the EXIF data. Has Windows and Mac versions:
http://www.exifpurge.com/
As for a tool that would work in your android build process, that needs further searching. But at least 'EXIF removal android library' are good keywords to start with
Lossless compression
Another alternative is researching lossless compression. I've used them in the past in web development. In my case, I used libraries which worked from the command line together with 'grunt' a build tool.
A quick google search showed the following site which works direct from your browser.
https://compressor.io/compress

How to set camera resolution in Android with OpenCV?

I'm trying to develop an app for Android, and I would need to get uncompressed pictures with a resolution as high as possible from the camera. I tried takePicture's rawCallback and postviewCallback, but they are not working.
Right now I'm trying with OpenCV (version 2.4) using VideoCapture, but I'm stuck in the default 960x720, which is poor for what I need; and my phone, a Samsung Galaxy S3, is able to provide, theoretically, up to 8Mpx (3,264×2,448 for pictures, and 1,920×1,080 for video, according to Wikipedia). VideoCapture.set(Highgui.CV_CAP_PROP_FRAME_WIDTH/HEIGHT, some number) makes the camera return a black image as far as I've found.
Is there any way to obtain a higher resolution, either through OpenCV or with the Android API, without compressing?
I'm really sorry if this has been asked before; I have been looking for days and I have found nothing.
Thank you for your time!
EDIT: Although it is not exactly what I was asking, I found that there is a way to do something very similar: if you set an OnPreviewCallback for the Camera, using setPreviewCallback, you do get the raw picture data from the camera (at least in the S3 I'm working with). I leave it here in case somebody finds it useful in the future.
EDIT: A partial solution is explained in an answer below. To sum up,
vc.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, desiredFrameWidth);
vc.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, desiredFrameHeight);
works under some conditions; please see below for further detail.
You have to get supported camera preview resoultions by calling getSupportedPreviewSizes.
After this you can set any resolution with method setPreviewSize. And don't forget to setParameters in the end. Actally many OpenCV Android examples contain this information (look at sample3).
In case anybody ever finds this useful, I found a (partial) solution: If your VideoCapture variable is called vc, this should work:
vc.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, desiredFrameWidth);
vc.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, desiredFrameHeight);
Mind that the combination of width and height must be one of the supported picture formats for your camera, otherwise it will just get a black image. You can get those through Camera.Parameters.getSupportedPictureSizes().
However, setting a high resolution appears to exceed the YUV conversion buffer's capacity, so I'm still struggling with that. I'm going to make a new separate question for that, to keep everything clearer: new thread
setPreviewSize does not set picture resolution. setPictureSize does.

Does Android need to load a complete Bitmap from a file before sampling it down?

In: Decoding bitmaps in Android with the right size - it is posted that sampling down a bitmap may still lead to memory errors.
Is this issue still valid for newer versions of Android?
Does this mean that before sampling down, Android needs to load the full-size bitmap into memory? I believe this uses native memory, since image handling is implemented in native code.
Here is how you can get the available memory amount:
Runtime.getRuntime().maxMemory()
and here is an interesting blog about memory:
http://codelog.dexetra.com/getting-around-android-memory-blues
The problem with Android is ou never know when you may run ou of memory and the app just crashes. That is why you should try to avoid loading too large bimaps (I usually use maximum of 800 /600 or something like that depending on the screen orientation....)
If loading several bitmaps like for gallery or other view group you should use weak reference:
http://developer.android.com/reference/java/lang/ref/WeakReference.html
Also if you look at the example in the link you provided the scaling first decodes only bounds and then decides on the scale to use.
When you don't need a bitmap anymore call:
bitmap.recycle();
Newer versions might have more physical memory but it's still limited to whatever is the system stack size; that way, programming bitmap still should be done very carefully with the amount of memory used.
On this years Google I/O (2012) there was a great presentation named "Doing more with less" that shows some very nice caching techniques you should look into. I'm sure you can find this video on YouTube Android Developers account.
Found the video: http://www.youtube.com/watch?v=gbQb1PVjfqM

Large app size due to images. How to compress .PNG images?

I am developing an app which has a lot of images to work on due to which the size of my app has become very large. I want to compress or something like that to reduce the size of app. Any idea?
.png-files which are placed in the res/drawable are automatically optimized when compiling your app:
Bitmap files may be automatically optimized with lossless image
compression by the aapt tool during the build process. For example, a
true-color PNG that does not require more than 256 colors may be
converted to an 8-bit PNG with a color palette. This will result in an
image of equal quality but which requires less memory. So be aware
that the image binaries placed in this directory can change during the
build. If you plan on reading an image as a bit stream in order to
convert it to a bitmap, put your images in the res/raw/ folder
instead, where they will not be optimized.
That being said, you have some more options to try. There is a good talk on this topic from Google I/O 2016 called "Image Compression for Android Developers", which outlines the possibilities, explains their up and downsides and gives some general best practices.
If the size of your application is to high to be published on the market, you'll can either
ship your app without the images and load them from the internet to the phones SD-card when the app is first started
Use Androids own APK Extension Files, which is basically the same but you don't have to do everything yourself.
Use pngquant or posterizer to reduce size of PNG images (these tools are lossy, but give significant savings).
You can also optimize them with PNGOUT, which is one of the best lossless optimizers.
I've written Mac GUI for those.
Always use PNG (.png) images.
And compress it online by uploading your images to
https://tinypng.com/
Simple and sober, always work. You are welcome. :)
There is also a better way to use AndEngine, it saves you from making layout for each phone. And there is no need to use different images for different dpi phones.
Do you use 9-patches for backgrounds? Also you can use imagemagick or anything similar to compress a batch or images.
Try and use ".png".
Use 9-patch images for backgrounds.
If you have title bars, headers with vertical gradients, always use 1-pixel width gradient images. This is a super saver.
If you manage to get hold of Photoshop, they have the option to save images for web/mobile devices. Helps in making really small sized images with good quality.
If u r supporting multiple devices, maintain different versions of the images only for those that are really necessary.

Categories

Resources