How to reduce image size in 1 MB

I want my application to download an image with no size limit, but in the code I want to resize the image by 1 MB if the image is larger than the size. I tried many ways, but I could not find the code for the requirement that I mentioned above.

This time I tried this:

public void scaleDown() {
    int width = stdImageBmp.getWidth();
    int height = stdImageBmp.getHeight();
    Matrix matrix = new Matrix();
    float scaleWidth = ((float) MAX_WIDTH) / width;
    float scaleHeight = ((float) MAX_HEIGHT) / height;


    matrix.postScale(scaleWidth, scaleHeight);
    stdImageBmp = Bitmap.createBitmap(stdImageBmp, 0, 0, width, height, matrix, true);

    File Image = new File("path");


    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    //compress bmp
    stdImageBmp.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
    byte[] byteArray = byteArrayOutputStream.toByteArray();


    imgViewStd.setImageBitmap(stdImageBmp);
    Log.d("resizedBitmap", stdImageBmp.toString());

    width = stdImageBmp.getWidth();
    height = stdImageBmp.getHeight();
    System.out.println("imgWidth" + width);
    System.out.println("imgHeight" + height);
}
+3
source share
3 answers

you can use this code to resize the bitmap and for image sizes <1MB I recommend using resolution 480x640

public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // "RECREATE" THE NEW BITMAP
        return Bitmap.createBitmap(
                bm, 0, 0, width, height, matrix, false);
    }
+4
source

, , , , . ( while)

: , ARGB_8888. . Android .

/**
 * Method to scale the Bitmap to respect the max bytes
 *
 * @param input    the Bitmap to scale if too large
 * @param maxBytes the amount of bytes the Image may be
 * @return The scaled bitmap or the input if already valid
 * @Note: The caller of this function is responsible for recycling once the input is no longer needed
 */
public static Bitmap scaleBitmap(final Bitmap input, final long maxBytes) {
    final int currentWidth = input.getWidth();
    final int currentHeight = input.getHeight();
    final int currentPixels = currentWidth * currentHeight;
    // Get the amount of max pixels:
    // 1 pixel = 4 bytes (R, G, B, A)
    final long maxPixels = maxBytes / 4; // Floored
    if (currentPixels <= maxPixels) {
        // Already correct size:
        return input;
    }
    // Scaling factor when maintaining aspect ratio is the square root since x and y have a relation:
    final double scaleFactor = Math.sqrt(maxPixels / (double) currentPixels);
    final int newWidthPx = (int) Math.floor(currentWidth * scaleFactor);
    final int newHeightPx = (int) Math.floor(currentHeight * scaleFactor);
    Timber.i("Scaled bitmap sizes are %1$s x %2$s when original sizes are %3$s x %4$s and currentPixels %5$s and maxPixels %6$s and scaled total pixels are: %7$s",
            newWidthPx, newHeightPx, currentWidth, currentHeight, currentPixels, maxPixels, (newWidthPx * newHeightPx));
    final Bitmap output = Bitmap.createScaledBitmap(input, newWidthPx, newHeightPx, true);
    return output;
}

:

// (1 MB)
final long maxBytes = 1024 * 1024; 
// Scale it
final Bitmap scaledBitmap = BitmapUtils.scaleBitmap(yourBitmap, maxBytes);
if(scaledBitmap != yourBitmap){
    // Recycle the bitmap since we can use the scaled variant:
    yourBitmap.recycle();
} 
// ... do something with the scaled bitmap

0

, . , , , , .

. JPG

Bitmap.createScaledBitmap(input, newWidthPx, newHeightPx, true)

, , .

, MAX_IMAGE_SIZE = 1024000, 350 2,33 . ? . 4, Google Pixel.

, , . A WHILE LOOP! ,

private fun scaleBitmap() {
    if (originalFile.length() > MAX_IMAGE_SIZE) {
        var streamLength = MAX_IMAGE_SIZE
        var compressQuality = 100
        val bmpStream = ByteArrayOutputStream()
        while (streamLength >= MAX_IMAGE_SIZE) {
            bmpStream.use {
                it.flush()
                it.reset()
            }

            compressQuality -= 8
            val bitmap = BitmapFactory.decodeFile(originalFile.absolutePath, BitmapFactory.Options())
            bitmap.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream)
            streamLength = bmpStream.toByteArray().size
        }

        FileOutputStream(compressedFile).use {
            it.write(bmpStream.toByteArray())
        }
    }
}

I think this approach will use exponential time depending on image resolution. A 9 MB image takes up to 12 seconds to compress to 1 MB. Good quality. You can configure this by decreasing the original raster resolution (which looks like a constant operation) by doing:

options.inSampleSize = 2;

What we need to do is somehow calculate the quality compression for any image. There should be math around this so that we can determine compressQuality from the original image size or width + height.

0
source

Source: https://habr.com/ru/post/1686101/


All Articles