【问题标题】:How to generate proper scaled bitmap to upload that to server faster?如何生成适当的缩放位图以更快地将其上传到服务器?
【发布时间】:2018-05-23 09:04:47
【问题描述】:

目前我正在使用mulitpart/form-data 将图像上传到服务器。在 node.js 服务器端,图像的存储没有任何问题。但是将图片上传到服务器需要很多时间。我尝试在上传位图之前重新缩放它们,但在大多数情况下,图片上传的尺寸比原始图像大,例如 200kb 的图片变成了 400kb 之类的东西。所以,我想知道如何正确缩放位图并以高效的速度将它们高质量地上传到服务器?

位图缩放代码:

bmp = MediaStore.Images.Media.getBitmap(ctx.getContentResolver(), uri);
                    int maxSize=700;
                    int outWidth;
                    int outHeight;
                    int inWidth = bmp.getWidth();
                    int inHeight = bmp.getHeight();
                    if(inWidth > inHeight){
                        outWidth = maxSize;
                        outHeight = (inHeight * maxSize) / inWidth;
                    } else {
                        outHeight = maxSize;
                        outWidth = (inWidth * maxSize) / inHeight;
                    }

                    final Bitmap new_bitmap = Bitmap.createScaledBitmap(bmp, outWidth, outHeight, false);

将位图保存到存储中:

void saveImage(String imgName, Bitmap bm) throws IOException {
    //Create Path to save Image
    File file_path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES + "/Infinity"); //Creates app specific folder
    file_path.mkdirs();
    File imageFile = new File(file_path, imgName + ".png"); // Imagename.png
    FileOutputStream out = new FileOutputStream(imageFile);
    try {
        bm.compress(Bitmap.CompressFormat.PNG, 100, out); // Compress Image
        out.flush();
        out.close();


        // Tell the media scanner about the new file so that it is
        // immediately available to the user.
        MediaScannerConnection.scanFile(ctx, new String[]{imageFile.getAbsolutePath()}, null, new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String pathi, Uri uri) {
                Log.i("ExternalStorage", "Scanned " + file_path + ":");
                Log.i("ExternalStorage", "-> uri=" + uri);

                parts.add(prepareFilePart("photo", pathi));

                    RequestBody description = createPartFromString(obji.toString());

                    FileUploadService service = ServiceGenerator.createService(FileUploadService.class);

                    Call<ResponseBody> call = service.uploadMultipleFilesDynamic(description, parts);

                    call.enqueue(new Callback<ResponseBody>() {
                        @Override
                        public void onResponse(Call<ResponseBody> call,
                                               Response<ResponseBody> response) {
                            Log.v("Upload", "success");

                            Intent i=new Intent(ctx,Home_Screen.class);
                            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NO_ANIMATION);
                            startActivity(i);
                        }

                        @Override
                        public void onFailure(Call<ResponseBody> call, Throwable t) {
                            if(t.getMessage()!=null) {
                                Log.e("Upload error:", t.getMessage());
                                Toast.makeText(ctx, t.getMessage(), Toast.LENGTH_LONG).show();
                                //Don't toast t.getMessage it would show the ip address which is bad
                            }
                        }
                    });

                    //Toast.makeText(ctx, "Downloaded Successfully", Toast.LENGTH_SHORT).show();

            }
        });
    } catch (Exception e) {
        throw new IOException();
    }
}

【问题讨论】:

  • 一个选项是压缩图像然后上传。也可以通过改造上传。
  • 非常感谢您的关注,您能帮我压缩图像吗? @ZeeshanSardar
  • outWidth = maxSize;。你总是给它最大尺寸。即使在与较小。为什么?
  • 我只是在下面回答,希望对你有帮助。
  • 您以 JPG 开头,以 PNG 结尾?

标签: android image-uploading android-bitmap


【解决方案1】:

试试这个,这是一个有效的解决方案。

private uploadPostImage(String imagePath) throws Exception {
    String orientation = "Portrait";
    Bitmap bm = null;
    try {
        bm = checkForRotation(imagePath);
        if (bm.getHeight() > bm.getWidth()) {
            orientation = "Portrait";
        } else if (bm.getWidth() > bm.getHeight()) {
            orientation = "Landscape";
        } else {
            orientation = "Portrait";
        }
    } catch (Exception e) {
        Log.e(e.getClass().getName(), e.getMessage());
    }
    if(bm.getWidth()>1000)
    {
        bm = getResizedBitmap(bm,1000);
    }

    try {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
        byte[] data = bos.toByteArray();

        /*
        /....
           Multipart uploading work
        ..../   
        */

    } catch (Exception e) {
        Log.e(e.getClass().getName(), e.getMessage());
    }
}

public Bitmap checkForRotation(String filename) {

    Bitmap bitmap = BitmapFactory.decodeFile(filename);
    int tmpHeight, tmpWidth;
    tmpWidth = bitmap.getWidth();
    tmpHeight = bitmap.getHeight();
    if (tmpWidth > tmpHeight)
    {
        tmpWidth = 1000;
        tmpHeight = (bitmap.getHeight() * tmpWidth) / bitmap.getWidth();
    } else
    {
        tmpHeight = 1000;
        tmpWidth = (bitmap.getWidth() * tmpHeight) / bitmap.getHeight();
    }
    bitmap= Bitmap.createScaledBitmap(bitmap, tmpWidth, tmpHeight, true);

    ExifInterface ei = null;
    try {
        ei = new ExifInterface(filename);
        new ExifInterface(filename);
    } catch (IOException e) {
        e.printStackTrace();
    }
    int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
            ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        bitmap = rotateImage(bitmap, 90);
        break;
    case ExifInterface.ORIENTATION_ROTATE_180:
        bitmap = rotateImage(bitmap, 180);
        break;
    }
    return bitmap;
}

public Bitmap getResizedBitmap(Bitmap bm, int newWidth) {
    int width = bm.getWidth();
    int height = bm.getHeight();

    float ratio  = (float)width/(float)height;
    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float)newWidth/ratio) / height;

    // CREATE A MATRIX FOR THE MANIPULATION
    Matrix matrix = new Matrix();
    // RESIZE THE BIT MAP
    matrix.postScale(scaleWidth, scaleHeight);
    // RECREATE THE NEW BITMAP
    Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height,
            matrix, false);
    return resizedBitmap;
}

【讨论】:

  • 先生,我正在这样做,图像尺寸仍在增加
  • @anonymous,试试我编辑的答案,如果您遇到任何问题,请告诉我。
  • 非常感谢您的出色回答,但请您告诉我在获取缩放位图时应该使用什么 newWidth
  • 先生,它仍在增加图像大小
  • 好的,等我有时间再研究一下。
【解决方案2】:

这是一种压缩图像的方法。先把你要压缩的图片的路径发给这个方法。它将返回您压缩图像的路径,然后从该路径创建一个文件并上传。

public static String compressImage(String filePath) {
        try {
            //String filePath = getRealPathFromURI(imageUri);
            Bitmap scaledBitmap = null;
            BitmapFactory.Options options = new BitmapFactory.Options();
            //by setting this field as true, the actual bitmap pixels are not loaded in the memory. Just the bounds are loaded. If
            //you try the use the bitmap here, you will get null.
            options.inJustDecodeBounds = true;
            Bitmap bmp = BitmapFactory.decodeFile(filePath, options);
        int actualHeight = options.outHeight;
        int actualWidth = options.outWidth;

        //max Height and width values of the compressed image is taken as 816x612
        float maxHeight = 816.0f;
        float maxWidth = 612.0f;
        float imgRatio = actualWidth / actualHeight;
        float maxRatio = maxWidth / maxHeight;

        //width and height values are set maintaining the aspect ratio of the image
        if (actualHeight > maxHeight || actualWidth > maxWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = maxHeight / actualHeight;
                actualWidth = (int) (imgRatio * actualWidth);
                actualHeight = (int) maxHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = maxWidth / actualWidth;
                actualHeight = (int) (imgRatio * actualHeight);
                actualWidth = (int) maxWidth;
            } else {
                actualHeight = (int) maxHeight;
                actualWidth = (int) maxWidth;
            }
        }

        //setting inSampleSize value allows to load a scaled down version of the original image
        options.inSampleSize = calculateInSampleSize(options, actualWidth, actualHeight);
        //inJustDecodeBounds set to false to load the actual bitmap
        options.inJustDecodeBounds = false;
        //this options allow android to claim the bitmap memory if it runs low on memory
        options.inPurgeable = true;
        options.inInputShareable = true;
        options.inTempStorage = new byte[16 * 1024];
        try {
            //load the bitmap from its path
            bmp = BitmapFactory.decodeFile(filePath, options);
        } catch (OutOfMemoryError exception) {
            exception.printStackTrace();
        }
        try {
            scaledBitmap = Bitmap.createBitmap(actualWidth, actualHeight, Bitmap.Config.ARGB_8888);
        } catch (OutOfMemoryError exception) {
            exception.printStackTrace();
        }

        float ratioX = actualWidth / (float) options.outWidth;
        float ratioY = actualHeight / (float) options.outHeight;
        float middleX = actualWidth / 2.0f;
        float middleY = actualHeight / 2.0f;

        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale(ratioX, ratioY, middleX, middleY);

        Canvas canvas = new Canvas(scaledBitmap);
        canvas.setMatrix(scaleMatrix);
        canvas.drawBitmap(bmp, middleX - bmp.getWidth() / 2, middleY - bmp.getHeight() / 2, new Paint(Paint.FILTER_BITMAP_FLAG));

        //check the rotation of the image and display it properly
        ExifInterface exif;
        try {
            exif = new ExifInterface(filePath);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
            Log.d("EXIF", "Exif: " + orientation);
            Matrix matrix = new Matrix();
            if (orientation == 6) {
                matrix.postRotate(90);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 3) {
                matrix.postRotate(180);
                Log.d("EXIF", "Exif: " + orientation);
            } else if (orientation == 8) {
                matrix.postRotate(270);
                Log.d("EXIF", "Exif: " + orientation);
            }
            scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0,
                    scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix,
                    true);
        } catch (IOException e) {
            e.printStackTrace();
        }

        FileOutputStream out = null;
        //String filename = getFilename();
        String filename = getFilename();
        try {
            out = new FileOutputStream(filename);
            //write the compressed bitmap at the destination specified by filename.
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        return filename;
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
    return null;
}

【讨论】:

  • 非常感谢您抽出宝贵的时间,先生,但首先我需要获取位图,所以请您发布任何方法以获得正确的缩放位图
【解决方案3】:

使用 multipart 上传带有改造的图片,而不是任何其他网络库。

How to make images upload faster in an Android app?

【讨论】:

  • 我不是在问如何上传我是在问如何更快地上传它
猜你喜欢
  • 2014-11-17
  • 1970-01-01
  • 2013-07-30
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多