[Android]-调整图像大小以上传到服务器

6

我的服务器限制上传图片的大小为2MB。我想从安卓设备上传图片到服务器,我需要调整图片大小。有什么最好的方法可以调整图片大小?


裁剪图像? - V-rund Puro-hit
@vrundpurohit 是的,我有一张5MB的图片,我想将其调整为2MB。 - Danh Nguyen
你可以使用_GZip_,也可以将图像作为字节数组发送! - Piyush
请查看此链接:如何在上传到服务器之前减小图像文件大小 - V-rund Puro-hit
请查看此链接:https://dev59.com/dGMl5IYBdhLWcg3wRlLo - user6543597
图像调整大小会消耗大量的CPU功率和能源。您的服务器应该进行调整大小。 - dieter
4个回答

14

使用以下代码。使用“MAX_IMAGE_SIZE”指定您的最大文件大小(以千字节为单位)。在此代码中,首先我调整图像大小,然后压缩它。请参阅代码中的注释以更好地理解逻辑。

     public static String resizeAndCompressImageBeforeSend(Context context,String filePath,String fileName){
     final int MAX_IMAGE_SIZE = 700 * 1024; // max final file size in kilobytes

     // First decode with inJustDecodeBounds=true to check dimensions of image
     final BitmapFactory.Options options = new BitmapFactory.Options();
     options.inJustDecodeBounds = true;
     BitmapFactory.decodeFile(filePath,options);

     // Calculate inSampleSize(First we are going to resize the image to 800x800 image, in order to not have a big but very low quality image.
     //resizing the image will already reduce the file size, but after resizing we will check the file size and start to compress image
     options.inSampleSize = calculateInSampleSize(options, 800, 800);

     // Decode bitmap with inSampleSize set
     options.inJustDecodeBounds = false;
     options.inPreferredConfig= Bitmap.Config.ARGB_8888;

     Bitmap bmpPic = BitmapFactory.decodeFile(filePath,options);


     int compressQuality = 100; // quality decreasing by 5 every loop.
     int streamLength;
     do{
         ByteArrayOutputStream bmpStream = new ByteArrayOutputStream();
         Log.d("compressBitmap", "Quality: " + compressQuality);
         bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream);
         byte[] bmpPicByteArray = bmpStream.toByteArray();
         streamLength = bmpPicByteArray.length;
         compressQuality -= 5;
         Log.d("compressBitmap", "Size: " + streamLength/1024+" kb");
     }while (streamLength >= MAX_IMAGE_SIZE);

     try {
         //save the resized and compressed file to disk cache
         Log.d("compressBitmap","cacheDir: "+context.getCacheDir());
         FileOutputStream bmpFile = new FileOutputStream(context.getCacheDir()+fileName);
         bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpFile);
         bmpFile.flush();
         bmpFile.close();
     } catch (Exception e) {
         Log.e("compressBitmap", "Error on saving file");
     }
     //return the path of resized and compressed file
     return  context.getCacheDir()+fileName;
 }



 public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
     String debugTag = "MemoryInformation";
     // Image nin islenmeden onceki genislik ve yuksekligi
     final int height = options.outHeight;
     final int width = options.outWidth;
     Log.d(debugTag,"image height: "+height+ "---image width: "+ width);
     int inSampleSize = 1;

     if (height > reqHeight || width > reqWidth) {

         final int halfHeight = height / 2;
         final int halfWidth = width / 2;

         // Calculate the largest inSampleSize value that is a power of 2 and keeps both
         // height and width larger than the requested height and width.
         while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
             inSampleSize *= 2;
         }
     }
     Log.d(debugTag,"inSampleSize: "+inSampleSize);
     return inSampleSize;
 }

为什么这个答案比其他答案更好呢?因为它可以压缩文件大小和提高质量,即使它更加复杂。 - Carlos.V
1
很棒的解决方案。帮了我很多忙! - Nikaoto
使用这个函数会节省多少空间? - ralphgabb
我们可以如何定义 int reqWidth, int reqHeight,因为我必须保持图像的原始性并在不同设备上显示,非常感谢任何帮助。 - Awadesh

0

在将图像编码为字符串后,您还可以这样做:将其压缩并计算保存图像之前所需的长度。在这种情况下,如果图像太大,用户将被迫更改图像。我假设您已经对图像进行了编码。

     long myBitmapLength = myEncodedImage.getBytes().length/1024;
       if(myBitmapLength < 200){
           //allow saving 
     }

0

修复图像分辨率和文件大小。

private const val TAG = "Compressor"
private const val START_QUALITY = 100
private const val QUALITY_DECREASE_STEP = 10
private const val DEFAULT_SIZE_LIMIT = 512_000
private const val MARGIN = 30

//image resolution 1024*768
private const val LONG_SIZE = 1024
private const val SHORT_SIZE = 768

object Compressor {
    private val FORMAT = Bitmap.CompressFormat.JPEG


    fun compressImage(
        imageFile: File,
        limitSize: Int = DEFAULT_SIZE_LIMIT,
        watermark: String? = null
    ): String {
        val originalBitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
        val bitmapWithWaterMark = mark(originalBitmap, watermark)

        val (newWidth, newHeight) = calculateNewWidthAndHeight(bitmapWithWaterMark)
        val resizedBitmap = getResizedBitmap(bitmapWithWaterMark, newWidth, newHeight)

        val stream = ByteArrayOutputStream()
        var quality = START_QUALITY
        //compressed Bitmap write to ByteArrayOutputStream
        resizedBitmap.compress(FORMAT, quality, stream)
        while (stream.size() > limitSize && quality > QUALITY_DECREASE_STEP) {
            stream.reset()
            quality -= QUALITY_DECREASE_STEP
            resizedBitmap.compress(FORMAT, quality, stream)
        }
        val base64String = Base64.encodeToString(stream.toByteArray(), Base64.DEFAULT)
        return base64String
    }

    private fun calculateNewWidthAndHeight(waterMarkBitmap: Bitmap): Pair<Int, Int> {
        val newWidth = if (isPortrait(waterMarkBitmap)) SHORT_SIZE else LONG_SIZE
        val newHeight = if (isPortrait(waterMarkBitmap)) LONG_SIZE else SHORT_SIZE
        return Pair(newWidth, newHeight)
    }

    private fun isPortrait(bitmap: Bitmap) = bitmap.height > bitmap.width

    private fun mark(source: Bitmap, watermark: String? = null): Bitmap {
        if (watermark == null) return source
        val width = source.width
        val height = source.height
        val result = Bitmap.createBitmap(width, height, source.config)
        val canvas = Canvas(result)
        canvas.drawBitmap(source, 0f, 0f, null)

        val paint = getPaint(18)
        val (widthPaint, heightPaint) = paint.getTextWidthAndHeight(watermark)

        //watermark background
        val backgroundPaint = getBackgroundPaint()
        canvas.drawRect(
            width - widthPaint - MARGIN,
            height - heightPaint * 2,
            width.toFloat(),
            height.toFloat() - heightPaint + MARGIN,
            backgroundPaint
        )

        //watermark text
        canvas.drawText(
            watermark,
            width - widthPaint,
            height - heightPaint,
            paint
        )

        return result
    }

    private fun getBackgroundPaint(): Paint {
        return Paint().apply {
            style = Paint.Style.FILL
            color = Color.BLACK
        }
    }

    private fun dpToPx(dp: Int): Float {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dp.toFloat(),
            App.resources.displayMetrics
        )
    }


    private fun getPaint(textSize: Int, isShadowEnable: Boolean = false): Paint {
        return Paint(Paint.ANTI_ALIAS_FLAG).apply {
            setTextSize(dpToPx(textSize))
            typeface = Typeface.create(Typeface.DEFAULT, Typeface.BOLD)

            if (isShadowEnable) {
                setShadowLayer(2f, 2f, 2f, Color.BLACK)
            }

            color = Color.WHITE
            textAlign = Paint.Align.LEFT
        }
    }

    private fun Paint.getTextWidthAndHeight(text: String): Pair<Float, Float> {
        val baseline = -this.ascent() // ascent() is negative
        val width: Float = this.measureText(text) + dpToPx(8)
        val height: Float = baseline + this.descent() + dpToPx(4)
        return Pair(width, height)
    }


    private fun getResizedBitmap(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
        val width = bitmap.width
        val height = bitmap.height
        val scaleWidth = newWidth.toFloat() / width
        val scaleHeight = newHeight.toFloat() / height
        // CREATE A MATRIX FOR THE MANIPULATION
        val matrix = Matrix()
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight)

        // "RECREATE" THE NEW BITMAP
        val resizedBitmap = Bitmap.createBitmap(
            bitmap, 0, 0, width, height, matrix, false
        )
        bitmap.recycle()
        return resizedBitmap
    }
}

0
Bitmap scaledBitmap = scaleDown(realImage, MAX_IMAGE_SIZE, true);

缩小比例方法:

public static Bitmap scaleDown(Bitmap realImage, float maxImageSize,
    boolean filter) {
float ratio = Math.min(
        (float) maxImageSize / realImage.getWidth(),
        (float) maxImageSize / realImage.getHeight());
int width = Math.round((float) ratio * realImage.getWidth());
int height = Math.round((float) ratio * realImage.getHeight());

Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width,
        height, filter);
return newBitmap;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接