1

ユーザーが写真を撮ることができるアプリケーションを入手しました。写真が撮られた後、ユーザーはそれを私のウェブサーバーに送信できます。ただし、これを行う前に、ビットマップのサイズを変更する必要があります。一貫したサイズを Web サーバーに送信したいからです。

とにかく、ビットマップをメモリにロードして操作するために使用するコードは、多くのメモリを占有しているようです。このコードは現在使用されています:

    /*
     *  This method is used to calculate image size.
     *  And also resize/scale image down to 1600 x 1200
     */
    private void ResizeBitmapAndSendToWebServer(string album_id) {

        Bitmap bm = null;
                    // This line is taking up to much memory each time..
        Bitmap bitmap = MediaStore.Images.Media.GetBitmap(Android.App.Application.Context.ApplicationContext.ContentResolver,fileUri);

                    /*
                     * My question is : Could i do the next image manipulation
                     * before i even load the bitmap into memory?
                     */
        int width = bitmap.Width;
        int height = bitmap.Height;

        if (width >= height) { // <-- Landscape picture

            float scaledWidth = (float)height / width;

            if (width > 1600) {
                bm = Bitmap.CreateScaledBitmap (bitmap, 1600, (int)(1600 * scaledWidth), true);
            } else {
                bm = bitmap;
            }
        } else {

            float scaledHeight = (float)width / height;

            if (height > 1600) {
                bm = Bitmap.CreateScaledBitmap (bitmap, (int)(1600 * scaledHeight), 1600 , true);
            } else {
                bm = bitmap;
            }

        }
                    // End of question code block.

        MemoryStream stream = new MemoryStream ();
        bitmap.Compress (Bitmap.CompressFormat.Jpeg, 80, stream);
        byte[] bitmapData = stream.ToArray ();
        bitmap.Dispose ();

        app.api.SendPhoto (Base64.EncodeToString (bitmapData, Base64Flags.Default), album_id);

    }

このようなメモリの問題を解決するための適切でクリーンな方法は何でしょうか?

編集1:

他の投稿を読んだ後、自分のコードで非効率的なことをしていることが明らかになりました。これは、段階的に、私が行ってきたことです:

  1. 完全なビットマップをメモリにロードします。
  2. 風景であるかどうかを決定します。
  3. 次に、正しい寸法で新しいビットマップを作成します。
  4. 次に、このビットマップをバイト配列に変換します
  5. 初期ビットマップの破棄。(ただし、スケーリングされたビットマップをメモリから削除しないでください)。

私が本当にすべきこと:

  1. 次のコマンドを使用して、メモリにロードせずに実際のビットマップの寸法を決定します。

    private void FancyMethodForDeterminingImageDimensions() {
    
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.InJustDecodeBounds = true;
    
        BitmapFactory.DecodeFile(fileUri.Path, options);
    
        // Now the dimensions of the bitmap are known without loading
        // the bitmap into memory.
        // I am not further going to explain this, i think the purpose is
        // explaining enough.
        int outWidth = options.OutWidth;
        int outHeight = options.OutHeight;
    
    }
    

true に設定すると、デコーダーは null (ビットマップなし) を返しますが、out... フィールドは引き続き設定されるため、呼び出し元はピクセルにメモリを割り当てることなくビットマップをクエリできます。

  1. 今、私は本当の次元を知っています。そのため、メモリにロードする前にダウンサンプリングできます。
  2. (私の場合)ビットマップをbase64文字列に変換して送信します。
  3. メモリがクリアされるようにすべてを破棄します。

開発マシンにいないため、現在これをテストできません。これが正しい方法である場合、誰かが私にフィードバックを与えることができますか? それは高く評価されます。

4

1 に答える 1

2
        private void ResizeBitmapAndSendToWebServer(string album_id) {

            BitmapFactory.Options options = new BitmapFactory.Options ();
            options.InJustDecodeBounds = true; // <-- This makes sure bitmap is not loaded into memory.
            // Then get the properties of the bitmap
            BitmapFactory.DecodeFile (fileUri.Path, options);
            Android.Util.Log.Debug ("[BITMAP]" , string.Format("Original width : {0}, and height : {1}", options.OutWidth, options.OutHeight) );
            // CalculateInSampleSize calculates the right aspect ratio for the picture and then calculate
            // the factor where it will be downsampled with.
            options.InSampleSize = CalculateInSampleSize (options, 1600, 1200);
            Android.Util.Log.Debug ("[BITMAP]" , string.Format("Downsampling factor : {0}", CalculateInSampleSize (options, 1600, 1200)) );
            // Now that we know the downsampling factor, the right sized bitmap is loaded into memory.
            // So we set the InJustDecodeBounds to false because we now know the exact dimensions.
            options.InJustDecodeBounds = false;
            // Now we are loading it with the correct options. And saving precious memory.
            Bitmap bm = BitmapFactory.DecodeFile (fileUri.Path, options);
            Android.Util.Log.Debug ("[BITMAP]" , string.Format("Downsampled width : {0}, and height : {1}", bm.Width, bm.Height) );
            // Convert it to Base64 by first converting the bitmap to
            // a byte array. Then convert the byte array to a Base64 String.
            MemoryStream stream = new MemoryStream ();
            bm.Compress (Bitmap.CompressFormat.Jpeg, 80, stream);
            byte[] bitmapData = stream.ToArray ();
            bm.Dispose ();

            app.api.SendPhoto (Base64.EncodeToString (bitmapData, Base64Flags.Default), album_id);

        }
于 2013-07-14T11:10:20.660 に答える