0

I am frustrating very long time on this problem. I have special case: I need resize (downscale) large existing image that stored in file and save it to new file. I do not show this image in image view, so techniques like use Glide, Picasso or options.inJustDecodeBounds = true will not help in this case. For example I have 8k image and I need to downscale it to 4K and then save to new file. On low end devices I will most likely see OOM exception when I will use options.inJustDecodeBounds = true, calculate inSampleSize and then call BitmapFactory.decodeResource(res, resId, options) because it will try to allocate memory for 4K bitmap (result bitmap will be stored in memory before save to disk). Any suggestions?

Milo
  • 3,365
  • 9
  • 30
  • 44
Battlevisek
  • 103
  • 1
  • 4
  • 1
    Check the answer: https://stackoverflow.com/questions/32121058/most-memory-efficient-way-to-resize-bitmaps-on-android – emandt Jan 03 '19 at 14:19
  • Both of these solutions are not suitable because I will finally get 4K bitmap object before save it to disk which will cause OOM – Battlevisek Jan 03 '19 at 14:22
  • 1
    There isn't any solution if you haven't enought available RAM. You could load in memory only 1/4th or 1/8th of the 8K bitmap, downscale each "piece" and then save them by writing their bytes directly to an OutputStream, but obliviously the resulting image could suffer of "noise near joints/conjunctions". A downscale procedure tries to merge all pixels accordling to resulting dimension, but if you don't have the whole Bitmap in memory the downscale cannot be done in the right way. – emandt Jan 03 '19 at 14:35
  • Thank you for explanation! What do you think about idea to develop custom class which can store image pixels on disk and use some kind of abstraction to manipulate pixels like pixels in array to use this object in custom downscaling method (replace ram with internal memory). Or it will be very slow and just waste of time? I searched for a library that can provide this functionality but did not find any results. – Battlevisek Jan 03 '19 at 14:50
  • Here you can find a good algorithm (different language of code): http://www.davdata.nl/math/bmresize.html The solution is to scan few lines (1/8th of the height?) and execute the algorithm on the most center lines discarding the first and the last. Then save resulting pixels to an InputStream. The best performance will be obtained by running the algorithm in Native JNI and return the pixels to Java using a NativeByteBuffer Java object. – emandt Jan 03 '19 at 15:56

1 Answers1

0

There is a class in the Android framework that can be used to decode only small regions of an image at a time: BitmapRegionDecoder. As @emandt mentioned, resizing it this way may give you some undesirable results, although you could experiment with picking different region sizes (perhaps some multiple of the rescale percentage could improve the results). Depending on your requirements these artifacts may not be a problem.

Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274