在发布前缩小图片尺寸

5

我有一个函数可以将文件(来自相机或图库的图片)发送到Web服务。

我想在上传之前减小fileUri的图像大小(例如50%)。

这个文件是来自图库或相机的图像。

这是我的postFile函数:

public static void postFile(Context context, String url, String fileUri, AsyncHttpResponseHandler responseHandler) {
    if (myCookieStore == null)
    {
        myCookieStore = new PersistentCookieStore(context);
        client.setCookieStore(myCookieStore);
    }

    File myFile = new File(Uri.parse(fileUri).getPath());

    RequestParams params = new RequestParams();
    try {
        params.put("profile_picture", myFile);
    } catch(FileNotFoundException e) {
        Log.d("error", "error catch");
    }
    Log.d("absolute url", "" + "*" + getAbsoluteUrl(url) + "*");
    client.post(context, getAbsoluteUrl(url), params, responseHandler);
}

我该怎么做?


你的问题表述不够清晰。从措辞来看,你可能想要减小图像尺寸,或者只是修改文件的路径/名称。不确定具体是哪种情况。 - IAmGroot
我想要减小图片尺寸(我编辑了我的问题)。 - Jéwôm'
请查看此链接:https://dev59.com/CmMl5IYBdhLWcg3wOU5g。 - Rajesh
有几个图像缩小服务的API可供使用。 - Zoe stands with Ukraine
6个回答

4

这里有一个库,可以将您的图片从MB压缩到KB,它非常强大,我已经使用了很多次,上传文件速度非常快。 链接

代码片段:compressedImageFile = Compressor.getDefault(this).compressToFile(actualImageFile);

它内部使用Google WebP格式,WebP是一种现代图像格式,为Web上的图像提供了优越的无损和有损压缩。使用WebP,网站管理员和Web开发人员可以创建更小、更丰富的图像,使Web更快。

该库在大小压缩方面表现出色,对于基于我的观察的大文件(如2MB以上),它做得非常好,但是需要解决一些内存泄漏问题,我通过使用LeakCanary解决了自己的问题,尽管每个开发人员都应该始终使用它。总的来说,这是一个很棒的库,您可以fork并根据需要使用。


你也可以扩展功能,如果愿意,你也可以使用响应式扩展让它更加实用。 - Remario
我不建议使用位图压缩来压缩您的文件,因为这样会造成质量损失,而且它也与PNG并不兼容。 - Remario
如果您的图像是PNG格式,请先使用Tiny PNG网站进行文件压缩,它可以很好地减小文件大小而不会影响质量。 - Remario
这个库有很多未解决的问题,更重要的是存在内存泄漏。 - Haris Qurashi
是的,我实际上坐下来逐步修改了大部分问题,并使用LeakCanary检查了内存泄漏并进行了修复。最终,我是一名软件工程师,这个库在减小大小方面非常出色。如果你是一个程序员,对于你的应用程序来说,这不应该是一个问题,你可以提交拉取请求并进行修改。明白了吗?这取决于你。 - Remario
最终它是开源的,所以这是可以预料的,你可以fork它并做你想做的事情,或者就让它保持原样,这取决于你。 - Remario

1

我在许多项目中都使用了这段代码,总是能够得到良好的结果。我记得如果我选择一个大小为5-7MB(来自12/13 MP相机)的图像,这段代码会返回一个大小为1MB或小于2MB的图像。

public static boolean validateUri(Uri uri) {
        if (uri == null)
            return false;
        else {
            String path = uri.getPath();
            return !(uri.equals(Uri.EMPTY) || path == null || path.equals("null"));
        }
    }

首先我们需要一张完整的图片,如果需要则旋转。
public static Bitmap getFullSizeImage(Context context, Uri uri) {
        String filePath;
        if (validateUri(uri) && uri.toString().contains("file"))
            filePath = uri.getPath();
        else
            filePath = getRealPathFromURI(context, uri, MediaStore.Images.Media.DATA);
        if (filePath == null)
            return null;
        try {
            int rotation = 0;
            ExifInterface exifInterface = new ExifInterface(filePath);
            int exifRotation = exifInterface.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
            if (exifRotation != ExifInterface.ORIENTATION_UNDEFINED) {
                switch (exifRotation) {
                    case ExifInterface.ORIENTATION_ROTATE_180:
                        rotation = 180;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_270:
                        rotation = 270;
                        break;
                    case ExifInterface.ORIENTATION_ROTATE_90:
                        rotation = 90;
                        break;
                }
            }
            Matrix matrix = new Matrix();
            matrix.setRotate(rotation);
            // you can use other than 400 as required width/height
            Bitmap sourceBitmap = getBitmapFromPath(400, filePath);
            if (sourceBitmap == null)
                return null;
            return Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(),
                    sourceBitmap.getHeight(), matrix, true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

现在我们需要从URI获取真实路径。
public static String getRealPathFromURI(Context context, Uri contentUri, String type) {
        Cursor cursor = null;
        String path = null;
        try {
            // String[] proj = { MediaStore.Images.Media.DATA };
            String[] projection = {type};
            cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
            if (cursor == null)
                return null;
            int columnIndex = cursor.getColumnIndexOrThrow(type);
            cursor.moveToFirst();
            path = cursor.getString(columnIndex);
            // we choose image from drive etc.
            if (path == null)
                path = getDocumentRealPathFromUri(context, contentUri);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return path;
    }

如果我们从Drive等地方选择一张图片,仍然需要给定URI的真实路径。
public static String getDocumentRealPathFromUri(Context context, Uri contentUri) {
        Cursor cursor = context.getContentResolver().query(contentUri, null,
                null, null, null);
        if (cursor == null)
            return null;
        cursor.moveToFirst();
        String documentId = cursor.getString(0);
        documentId = documentId.substring(documentId.lastIndexOf(":") + 1);
        cursor.close();
        cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + " = ? ",
                new String[]{documentId}, null);
        if (cursor == null)
            return null;
        cursor.moveToFirst();
        String path = cursor.getString(cursor
                .getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
        return path;
    }

现在我们有了所选图像的真实路径,因此我们可以使用样本大小从该路径获取位图。
public static Bitmap getBitmapFromPath(int size, String realPathFromURI) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(realPathFromURI, options);
        options.inSampleSize = calculateInSampleSizeUsingPower2(options, size, size);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(realPathFromURI, options);
    }

    public static int calculateInSampleSizeUsingPower2(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        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;
        }
        return inSampleSize;
    }

在此时,我们拥有一个压缩位图,如果对给定的位图执行Base64操作,我们可以再次压缩该位图。
public static String convertToBase64(Bitmap bitmap) {
        if (bitmap == null)
            return null;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)) {
            String base64 = encodeToString(byteArrayOutputStream.toByteArray(), DEFAULT);
            try {
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return base64;
        }
        return null;
    }

在您的服务器端,您可以解码Base64并将其转换回文件流以保存您的图像。
示例。
Bitmap bitmap = getFullSizeImage(context, selectedPhotoUri);
if(bitmap != null){
    String base64Image = convertToBase64(bitmap);
    if (base64Image != null) {
        RequestParams params = new RequestParams();
        try {
            params.put("title", "your_image_name");
            params.put("profile_picture", base64Image);
        } catch(FileNotFoundException e) {
            Log.d("error", "error catch");
        }
    }
}

注意 如果您不想执行Base64,可以使用位图将其转换为流并将其发送到服务器。


0
尝试使用此函数。如果位图的宽度或高度大于512,则它将把位图的大小减小到512。
public static Bitmap resizeBitmap(Bitmap bm) {
        if (bm.getWidth() > maxSize || bm.getHeight() > maxSize) {
            if (bm.getWidth() > bm.getHeight()) {
                newWidth = maxSize;
                newHeight = (bm.getHeight() * maxSize) / bm.getWidth();

                bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true);
                return bm;
            } else {
                newHeight = maxSize;
                newWidth = (bm.getWidth() * maxSize) / bm.getHeight();
                bm = Bitmap.createScaledBitmap(bm, newHeight, newWidth, true);
                return bm;
            }
        }
        return bm;
    }

你只需要将位图传递给这个方法。

从URI获取位图的方法是

BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;
        bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
                options);

谢谢,但我有一个字符串文件URI。我如何从这个字符串调整大小? - Jéwôm'
从URI获取位图。 - AbhayBohra

0

使用此代码可更改图像的宽度和高度

public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
    int width = bm.getWidth();
    int height = bm.getHeight();
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;
    Matrix matrix = new Matrix();
    matrix.postScale(scaleWidth, scaleHeight);
    Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
            matrix, false);

    return resizedBitmap;
}

您可以使用此代码来更改大小...这是最佳示例...

  private Bitmap decodeFile(File f){
   try {
    //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(new FileInputStream(f),null,o);

    //The new size we want to scale to
    final int REQUIRED_SIZE=70;

    //Find the correct scale value. It should be the power of 2.
    int scale=1;
    while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
        scale*=2;

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize=scale;
    return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
  } catch (FileNotFoundException e) {}
  return null;
  }

谢谢。但我不明白如何在我的代码中使用它。我必须先解码我的文件吗?我可以使用我的Uri吗? - Jéwôm'
通过这个代码,你可以从URI中获取文件:File myFile = new File(uri.getPath()); - Nithinlal

0
如果相机图像是JPEG格式,您可以使用位图压缩方法,例如:
Bitmap bitmap = BitmapFactory.decodeStream(...uri);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                int compression_factor = 50;    // represents 50% compression
                bitmap.compress(Bitmap.CompressFormat.JPEG, compression_factor, baos);

                byte[] image = baos.toByteArray();

               // now update web service asynchronously...
               ...
            } finally {
                baos.close();
            }

0

将图像转换为位图,然后使用以下方法

     public static Bitmap scaleBitmap(Bitmap bitmap, int newWidth, int newHeight) {
        Bitmap scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);

        float scaleX = newWidth / (float) bitmap.getWidth();
        float scaleY = newHeight / (float) bitmap.getHeight();
        float pivotX = 0;
        float pivotY = 0;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(scaleX, scaleY, pivotX, pivotY);

        Canvas canvas = new Canvas(scaledBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bitmap, 0, 0, new Paint(Paint.FILTER_BITMAP_FLAG));

        return scaledBitmap;
    }

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