SoFunction
Updated on 2025-04-10

Android picture compression (quality compression and size compression)

After investigating the method of image compression online and implementing it, it can be roughly believed that there are two types of compression: quality compression (not changing the size of the picture) and size compression (equivalent to compression on pixels); quality compression can generally be used for processing before uploading large images, which can save a certain amount of traffic. After all, mobile phones can take photos now and now, size compression can generally be used to generate thumbnails.

Both methods were implemented in my project, but I found that in the quality compression module, the original 1.9M picture was more than 3M after compression, which was very strange. After further investigation, I finally found the reason. The following blog says it clearly:

Android image compression summary

In summary, there are three forms of images: the file is on the hard disk, the stream is during network transmission, and the stream or bitmap is in the memory. The so-called quality compression can only achieve the impact on the file. You can convert a file into a bitmap and then to a file, or directly convert a bitmap into a file, the final file is compressed, but the middle bitmap is not compressed (or it is almost not compressed, I am not sure), because the size of bigmap in memory is calculated by pixels, that is, width * height. For quality compression, it will not change the pixels of the picture, so even if the quality is compressed, the memory share of bitmap has not decreased, but when you make a file, it does become smaller;

Since size compression reduces the pixels of the picture, it directly affects bitmap, and of course the final file is relatively smaller;

Finally, post the tools you summarized:

import javaioByteArrayInputStream; 
import javaioByteArrayOutputStream; 
import javaioFile; 
import javaioFileNotFoundException; 
import javaioFileOutputStream; 
import javaioIOException; 
 
import androidgraphicsBitmap; 
import androidgraphicsBitmapConfig; 
import androidgraphicsBitmapFactory; 
 
/** 
 * Image compress factory class 
 * 
 * @author 
 * 
 */ 
public class ImageFactory { 
 
  /** 
   * Get bitmap from specified image path 
   * 
   * @param imgPath 
   * @return 
   */ 
  public Bitmap getBitmap(String imgPath) { 
    // Get bitmap through image path 
    BitmapFactoryOptions newOpts = new BitmapFactoryOptions(); 
    newOptsinJustDecodeBounds = false; 
    newOptsinPurgeable = true; 
    newOptsinInputShareable = true; 
    // Do not compress 
    newOptsinSampleSize = 1; 
    newOptsinPreferredConfig = ConfigRGB_565; 
    return BitmapFactorydecodeFile(imgPath, newOpts); 
  } 
   
  /** 
   * Store bitmap into specified image path 
   * 
   * @param bitmap 
   * @param outPath 
   * @throws FileNotFoundException 
   */ 
  public void storeImage(Bitmap bitmap, String outPath) throws FileNotFoundException { 
    FileOutputStream os = new FileOutputStream(outPath); 
    bitmapcompress(BitmapCompressFormatJPEG, 100, os); 
  } 
   
  /** 
   * Compress image by pixel, this will modify image width/height 
   * Used to get thumbnail 
   * 
   * @param imgPath image path 
   * @param pixelW target pixel of width 
   * @param pixelH target pixel of height 
   * @return 
   */ 
  public Bitmap ratio(String imgPath, float pixelW, float pixelH) { 
    BitmapFactoryOptions newOpts = new BitmapFactoryOptions();  
    // Start reading the picture, and then set optionsinJustDecodeBounds back to true, that is, only read edges and not content    newOptsinJustDecodeBounds = true; 
    newOptsinPreferredConfig = ConfigRGB_565; 
    // Get bitmap info, but notice that bitmap is null now  
    Bitmap bitmap = BitmapFactorydecodeFile(imgPath,newOpts); 
      
    newOptsinJustDecodeBounds = false;  
    int w = newOptsoutWidth;  
    int h = newOptsoutHeight;  
    // The target size you want to scale    float hh = pixelH;// When setting the height to 240f, you can clearly see that the picture is reduced    float ww = pixelW;// Set the width to 120f, you can clearly see that the picture is reduced    // Zoom ratio.  Since it is fixed proportional scaling, only one of the data of height or width can be calculated    int be = 1;//be=1 means no scaling    if (w > h && w > ww) {// If the width is large, scale it according to the width fixed size      be = (int) (newOptsoutWidth / ww);  
    } else if (w < h && h > hh) {// If the height is high, it will be scaled according to the width.      be = (int) (newOptsoutHeight / hh);  
    }  
    if (be <= 0) be = 1;  
    newOptsinSampleSize = be;//Set the scaling ratio    // Start compressing the image, please note that optionsinJustDecodeBounds has been set back to false at this time    bitmap = BitmapFactorydecodeFile(imgPath, newOpts); 
    // After compressing the proportion, perform mass compression// return compress(bitmap, maxSize); // It doesn't make much sense to perform quality compression here, but instead consumes resources and deletes    return bitmap; 
  } 
   
  /** 
   * Compress image by size, this will modify image width/height 
   * Used to get thumbnail 
   * 
   * @param image 
   * @param pixelW target pixel of width 
   * @param pixelH target pixel of height 
   * @return 
   */ 
  public Bitmap ratio(Bitmap image, float pixelW, float pixelH) { 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    imagecompress(BitmapCompressFormatJPEG, 100, os); 
    if( ostoByteArray()length / 1024>1024) {//Judge if the image is greater than 1M, compress it to avoid overflowing when generating the image (BitmapFactorydecodeStream)      osreset();//Reset baos means clear baos      imagecompress(BitmapCompressFormatJPEG, 50, os);//Create 50% here, store the compressed data in baos    }  
    ByteArrayInputStream is = new ByteArrayInputStream(ostoByteArray());  
    BitmapFactoryOptions newOpts = new BitmapFactoryOptions();  
    //Start read the picture, and then set optionsinJustDecodeBounds back to true    newOptsinJustDecodeBounds = true; 
    newOptsinPreferredConfig = ConfigRGB_565; 
    Bitmap bitmap = BitmapFactorydecodeStream(is, null, newOpts);  
    newOptsinJustDecodeBounds = false;  
    int w = newOptsoutWidth;  
    int h = newOptsoutHeight;  
    float hh = pixelH;// When setting the height to 240f, you can clearly see that the picture is reduced    float ww = pixelW;// Set the width to 120f, you can clearly see that the picture is reduced    //Scaling ratio.  Since it is fixed proportional scaling, only one of the data of height or width can be calculated    int be = 1;//be=1 means no scaling    if (w > h && w > ww) {// If the width is large, scale it according to the width fixed size      be = (int) (newOptsoutWidth / ww);  
    } else if (w < h && h > hh) {// If the height is high, it will be scaled according to the width.      be = (int) (newOptsoutHeight / hh);  
    }  
    if (be <= 0) be = 1;  
    newOptsinSampleSize = be;//Set the scaling ratio    //Read the picture again, note that optionsinJustDecodeBounds has been set back to false at this time    is = new ByteArrayInputStream(ostoByteArray());  
    bitmap = BitmapFactorydecodeStream(is, null, newOpts); 
    //After compressing the proportion, then perform mass compression// return compress(bitmap, maxSize); // It doesn't make much sense to perform quality compression here, but instead consumes resources and deletes    return bitmap; 
  } 
   
  /** 
   * Compress by quality, and generate image to the path specified 
   * 
   * @param image 
   * @param outPath 
   * @param maxSize target will be compressed to be smaller than this size(kb) 
   * @throws IOException 
   */ 
  public void compressAndGenImage(Bitmap image, String outPath, int maxSize) throws IOException { 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    // scale 
    int options = 100; 
    // Store the bitmap into output stream(no compress) 
    imagecompress(BitmapCompressFormatJPEG, options, os);  
    // Compress by loop 
    while ( ostoByteArray()length / 1024 > maxSize) { 
      // Clean up os 
      osreset(); 
      // interval 10 
      options -= 10; 
      imagecompress(BitmapCompressFormatJPEG, options, os); 
    } 
     
    // Generate compressed image file 
    FileOutputStream fos = new FileOutputStream(outPath);  
    foswrite(ostoByteArray());  
    fosflush();  
    fosclose();  
  } 
   
  /** 
   * Compress by quality, and generate image to the path specified 
   * 
   * @param imgPath 
   * @param outPath 
   * @param maxSize target will be compressed to be smaller than this size(kb) 
   * @param needsDelete Whether delete original file after compress 
   * @throws IOException 
   */ 
  public void compressAndGenImage(String imgPath, String outPath, int maxSize, boolean needsDelete) throws IOException { 
    compressAndGenImage(getBitmap(imgPath), outPath, maxSize); 
     
    // Delete original file 
    if (needsDelete) { 
      File file = new File (imgPath); 
      if (fileexists()) { 
        filedelete(); 
      } 
    } 
  } 
   
  /** 
   * Ratio and generate thumb to the path specified 
   * 
   * @param image 
   * @param outPath 
   * @param pixelW target pixel of width 
   * @param pixelH target pixel of height 
   * @throws FileNotFoundException 
   */ 
  public void ratioAndGenThumb(Bitmap image, String outPath, float pixelW, float pixelH) throws FileNotFoundException { 
    Bitmap bitmap = ratio(image, pixelW, pixelH); 
    storeImage( bitmap, outPath); 
  } 
   
  /** 
   * Ratio and generate thumb to the path specified 
   * 
   * @param image 
   * @param outPath 
   * @param pixelW target pixel of width 
   * @param pixelH target pixel of height 
   * @param needsDelete Whether delete original file after compress 
   * @throws FileNotFoundException 
   */ 
  public void ratioAndGenThumb(String imgPath, String outPath, float pixelW, float pixelH, boolean needsDelete) throws FileNotFoundException { 
    Bitmap bitmap = ratio(imgPath, pixelW, pixelH); 
    storeImage( bitmap, outPath); 
     
    // Delete original file 
        if (needsDelete) { 
          File file = new File (imgPath); 
          if (fileexists()) { 
            filedelete(); 
          } 
        } 
  } 
   
} 

Android image compression summary

1. The existence form of the picture

1. File form (that is, it exists on the hard disk in binary form)

2. The form of stream (that is, it exists in memory in binary form)

form

The difference between these three forms: file form and stream form have no effect on the size of the picture. That is to say, if the SD card on your mobile phone is 100K, then reading into the memory through the stream form must also occupy 100K memory. Note that it is the form of stream, not the form of Bitmap. When the image exists in the form of Bitmap, the memory it occupies will instantly increase. I have tried to load the image in the form of 500K file into memory. When it exists in the form of Bitmap, it occupies nearly 10M memory. Of course, this increase multiple is not fixed.

Methods to detect three forms of picture size:

File form: ()

The form of stream: When reading the image file into the memory input stream, see its byte number

Bitmap: ()

2. Common compression methods

1. Compress the image when saving it to the local area, that is, compress the image when changing from Bitmap to File.

Features are: The image in the form of File is indeed compressed, but when you re-read the compressed file as Bitmap, the memory it occupies has not changed.

Method description: This method compresses the quality of the picture. Note that it will not reduce the pixels of the picture. For example, your picture is 300K and 1280*700 pixels. After this method, the image in File form is below 100 to facilitate uploading to the server. However, when you enter the memory and become a Bitmap, its pixels are still 1280*700. The methods for calculating the pixels of the picture are () and (). The picture is composed of pixels. What does each pixel contain? People who are familiar with PS know that pictures are composed of hues, brightness and saturation.

public static void compressBmpToFile(Bitmap bmp,File file){ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    int options = 80;//I personally like it starting from 80,    (, options, baos); 
    while (().length / 1024 > 100) {  
      (); 
      options -= 10; 
      (, options, baos); 
    } 
    try { 
      FileOutputStream fos = new FileOutputStream(file); 
      (()); 
      (); 
      (); 
    } catch (Exception e) { 
      (); 
    } 
  } 

The official documentation of this method also explains that it will reconstruct the image, but it is possible that the bit depth of the image (i.e., the color depth) and the transparency of each pixel will change. JPEG only supports opaque, which means that after compressing in jpeg format, the transparent elements in the original image will disappear. Therefore, this format is likely to cause distortion.

Since it has changed the display quality of the picture and compressed the image in File form and the pixels of the picture have not changed, it will take up no less memory when rereading the compressed file as Bitmap. (If you don't believe it, you can try it)

Because: () is the memory occupied by calculating its pixels, please see the official explanation: Returns the number of bytes used to store this bitmap's pixels.

2. When reading the image from local to memory, compress it, that is, the image changes from File form to Bitmap form

Features: By setting the sampling rate, the pixels of the picture are reduced, so that the Bitmap in memory can be compressed.

First look at a method: This method is to compress the Bitmap in memory in quality. From the above theory, we can find that the method is invalid and unnecessary, because you have read it into memory, and then compress it too much. Although some mobile phones will directly return a Bitmap when obtaining the system album picture, in this case, the returned Bitmap is compressed, and it is impossible to directly return a Bitmap in the original sound. The consequences can be imagined.

Method description: This method is to compress images in Bitmap form, that is, by setting the sampling rate, the pixels of Bitmap are reduced, thereby reducing the memory it occupies.

private Bitmap compressBmpFromBmp(Bitmap image) { 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    int options = 100; 
    (, 100, baos); 
    while (().length / 1024 > 100) {  
      (); 
      options -= 10; 
      (, options, baos); 
    } 
    ByteArrayInputStream isBm = new ByteArrayInputStream(()); 
    Bitmap bitmap = (isBm, null, null); 
    return bitmap; 
  } 

Let's look at another method:

  private Bitmap compressImageFromFile(String srcPath) { 
     newOpts = new (); 
     = true;//Read only edges, not content    Bitmap bitmap = (srcPath, newOpts); 
 
     = false; 
    int w = ; 
    int h = ; 
    float hh = 800f;// 
    float ww = 480f;// 
    int be = 1; 
    if (w > h && w > ww) { 
      be = (int) ( / ww); 
    } else if (w < h && h > hh) { 
      be = (int) ( / hh); 
    } 
    if (be <= 0) 
      be = 1; 
     = be;//Set the sampling rate     
     = Config.ARGB_8888;//This mode is default, no     = true;// Setting will be effective     = true;//.  Pictures are automatically recycled when the system memory is insufficient     
    bitmap = (srcPath, newOpts); 
// return compressBmpFromBmp(bitmap);//The original method called this method to attempt to perform secondary compression                  //It's actually invalid, just try it    return bitmap; 
  } 

Share a compression according to the image size:

public static void compressPicture(String srcPath, String desPath) { 
    FileOutputStream fos = null; 
    BitmapFactoryOptions op = new BitmapFactoryOptions(); 
 
    // Start reading the picture, and set optionsinJustDecodeBounds back to true    opinJustDecodeBounds = true; 
    Bitmap bitmap = BitmapFactorydecodeFile(srcPath, op); 
    opinJustDecodeBounds = false; 
 
    // Scale the size of the picture    float w = opoutWidth; 
    float h = opoutHeight; 
    float hh = 1024f;// 
    float ww = 1024f;// 
    // Maximum width or height 1024    float be = 0f; 
    if (w > h && w > ww) { 
      be = (float) (w / ww); 
    } else if (w < h && h > hh) { 
      be = (float) (h / hh); 
    } 
    if (be <= 0) { 
      be = 0f; 
    } 
    opinSampleSize = (int) be;// Set the scaling ratio. The larger the number, the smaller the image size    //Read the picture again, note that optionsinJustDecodeBounds has been set back to false at this time    bitmap = BitmapFactorydecodeFile(srcPath, op); 
    int desWidth = (int) (w / be); 
    int desHeight = (int) (h / be); 
    bitmap = BitmapcreateScaledBitmap(bitmap, desWidth, desHeight, true); 
    try { 
      fos = new FileOutputStream(desPath); 
      if (bitmap != null) { 
        bitmapcompress(BitmapCompressFormatJPEG, 100, fos); 
      } 
    } catch (FileNotFoundException e) { 
      eprintStackTrace(); 
    } 
  } 

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.