簡體   English   中英

在Android中壓縮圖像以上傳到服務器的過程

[英]Process to compress an image for uploading to a server in Android

在將圖像上傳到服務器之前,我想編寫自己的代碼來壓縮圖像。

我看到的那么多帖子像這樣 ,有很多其他的帖子也隨處可見,但現在只有代碼樣本。 實際上並沒有在任何地方解釋。 我無法從給定的代碼中理解。

我只是想了解壓縮圖像的整體方法,以便我可以自己開始編寫代碼。

我不是在尋找代碼,只是一個人壓縮圖像所需要遵循的步驟。 (就像在編寫程序之前編寫算法,即偽代碼)

我認為Chetan Joshi的回答是迄今為止最接近的。 但要進一步解釋,

“壓縮”圖像和“縮放”(調整大小)圖像是不同的。 由於您只想在上傳到服務器時減少網絡上的帶寬(kb / Mb),因此您很可能會談論“縮放”,因為這會對圖像的大小產生最大的影響。

請注意,與Android的其他答案一樣,您需要使用Bitmaps 您需要使用與位圖關聯的API調用來執行您想要的操作。

初始點:

如果您允許您的應用使用相機拍攝照片或從圖庫中選擇,您將獲得一個Uri,它允許您打開如下所示的InputStream:

InputStream is = getContext().getContentResolver().openInputStream(photoUri);

這是第一步。 下一部分是偽代碼,你想要這樣的東西:

  1. 獲取照片/所選圖片的InputStream 這只是表示圖像的字節流。
  2. 使用BitmapFactory.decodeStream(InputStream src)將流解碼為Bitmap
  3. 使用Bitmap.createScaledBitmap(src, dstWidth, dstHeight, filter);縮放(調整大小)位圖Bitmap.createScaledBitmap(src, dstWidth, dstHeight, filter); 您必須自己決定目的地寬度和目的地高度。 請參閱下一組偽代碼。
  4. 使用imageFormat.getBitmapCompressFormat(), 100, output)壓縮位圖imageFormat.getBitmapCompressFormat(), 100, output)其中輸出是ByteArrayOutputStream的實例
  5. 你現在可以調用output.toByteArray(); 得到字節。
  6. 字節是您要發送到服務器的字節。

請注意有關如何選擇要縮放到的目標寬度和高度:

  1. 確定最大高度和最大寬度,例如240 x 240.您將把它與位圖的實際高度和實際寬度進行比較。
  2. 如果太高(實際高度>最大高度),請計算最大高度/實際高度的比例因子
  3. 如果太寬(實際寬度>最大寬度),請計算最大寬度/實際寬度的縮放系數
  4. 您的實際比例因子是這兩個比例因子中的最小值
  5. 返回實際高度*縮放系數和實際寬度*縮放系數

總的來說,高級流程是這樣的:

  1. 打開圖像字節流
  2. 將字節轉換為位圖
  3. 縮放位圖
  4. 壓縮位圖
  5. 將位圖轉換回字節

Android中的圖像壓縮意味着我們正在使用Bitmaps,而我們正在壓縮任何大圖像,然后我們在Bitmap類中使用方法壓縮,但如果原始位圖和所需位圖的大小之間的差異太高,則位圖質量總是會降低。

要以高質量壓縮位圖,我們必須使用遞歸過程來壓縮任何位圖,而不是將任何位圖直接從原始高度寬度壓縮到所需的高度和寬度,我們應該使用3到5步壓縮圖像,例如,如果我們的圖像大小為1000x1000並且需要寬度和高度是300x300然后我們應用遞歸過程來執行此操作,如下所示:

1000 x 1000

850 x 850

650 x 650

300 x 300 

這樣我們的Bitmap質量沒有降低,但確保每次使用相同的位圖對象分配壓縮位圖時都不要創建新的位圖對象,否則你必須面對OutOfmemmory問題。

你可以使用android sdk - bitmap.compress();

ByteArrayOutputStream bos = new ByteArrayOutputStream();

if (myBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos)) {
    //image is now compressed into the output stream
    uploadImage(bos);
} else {
    //compress failed
}

你可以隨時查看android源代碼以了解更多信息,但如果你是一個Android開發人員,我認為花時間學習如何壓縮不應該是你的主要焦點,特別是當你有這么簡單的解決方案,如果你仍然認為你這樣做我將首先學習如何首先壓縮文件,然后我將移動到圖像,然后我會查看源代碼

由於您實際上並沒有尋找代碼,因此這里是學習圖像壓縮數據壓縮理論背后的思維過程的絕佳資源

有許多算法利用不同的技術來利用所涉及的不同變量。 計算復雜性,存儲空間,壓縮比和保留圖像質量都是這些不同算法(或文件格式)尋求優化的因素,通常有利於一個屬性而不是另一個屬性。 例如PNG vs JPEG,用於質量與空間

Java提供了ImageIO API,可以幫助您根據自己的質量和壓縮因素來壓縮圖像。 ImageWriterImageWriteParam提供開箱即用的功能。

您是否計划根據自己的要求定制自己的API?

如果不使用開箱即用的Java API,高級方法可能是:1)讀取圖像文件。 2)使用ImageIO,根據圖像類型獲取ImageWriter(jpeg,png等).3)從編寫器獲取ImageWriteParam對象,並根據您的要求設置壓縮參數。 4)寫下圖像。

如果它對您不起作用,請告訴我。

鏈接中的代碼描述的不是壓縮,而是以較低的密度對圖像進行采樣並對其進行縮減。 因此,它不是真正的壓縮,而是質量(像素數和大小)的減少,以使其更小。 良好的壓縮算法通常會找到一種方法來保存圖像,使用的空間更少,而不會過多地影響質量(使用數學和東西)。

裁剪圖像,然后發送到服務器。它工作正常,

將依賴項添加到gradle中,

compile 'com.soundcloud.android:android-crop:1.0.1@aar'

畫廊意圖,

private static final int PICK_FROM_FILE = 3;
private Uri mImageCaptureUri=null;
File sdCard = Environment.getExternalStorageDirectory();
String pathName;
File filepath;

Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, PICK_FROM_FILE);

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode != RESULT_OK)
        return;
     switch (requestCode) {
             case PICK_FROM_FILE:
               mImageCaptureUri = data.getData();
               // METHOD FOR CROP
               beginCrop(mImageCaptureUri);
               System.out.println("CHECK_GALLERY_path :" + mImageCaptureUri);
              break;
              case Crop.REQUEST_CROP:
              handleCrop(resultCode, data);
              break;
     }
  }

  private void beginCrop(Uri source) {
    Uri destination = Uri.fromFile(new File(getCacheDir(), "cropped"));
    Crop.of(source, destination).start(this);
 }

  private void handleCrop(int resultCode, Intent result) {

    if (resultCode == RESULT_OK) {

        mImageCaptureUri = Crop.getOutput(result);

        pathName = mImageCaptureUri.getPath();
        //uploadImageToServer();
        //  getImageUri(mImageCaptureUri);
                       Picasso.with(Activity_My_Account.this).load(mImageCaptureUri).into(getimage);          //IMAGE SAVE TO STORAGE
        getImageUri(mImageCaptureUri);
        System.out.println("path_name+++" + mImageCaptureUri);


    } else if (resultCode == Crop.RESULT_ERROR) {
        Toast.makeText(this, Crop.getError(result).getMessage(),        Toast.LENGTH_SHORT).show();
    }
}


    private void getImageUri(Uri mImageCaptureUri) {
     Bitmap photo = null;
     try {
        InputStream image_stream = getContentResolver().openInputStream(mImageCaptureUri);
        java.util.Date date = new java.util.Date();
         pathName = sdCard + "/" + "LEUF";
            File myDir = new File(pathName);
        System.out.println("GET_CHECK_PATH_NAME :" + pathName);
        myDir.mkdirs();
        Random generator = new Random();
        int n = 10000;
        n = generator.nextInt(n);
        String fname = "Image-" + n + ".jpg";
        File file = new File(myDir, fname);
        // if (file.exists()) file.delete();
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        Bitmap bitmapOrg = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(image_stream), 350, 350, false);
        photo.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
         filepath=file;
         try {
            // file.createNewFile();
            FileOutputStream fo = new FileOutputStream(file);
            fo.write(bytes.toByteArray());
            fo.flush();
            fo.close();
        } catch (IOException e) {

            e.printStackTrace();
        }
      //here call to upload image to server
        public void UploadProfilePic(filepath){
        }

     } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM