android: rotar una imagen de alta resolución genera un error de falta de memoria

Intento rotar una imagen en "onPictureTaken"

public void onPictureTaken(byte[] data, Camera camera) {
    String fileName = "last"+Calendar.getInstance().getTimeInMillis();
    String finalFilePath=null;
    File temp= Environment.getExternalStorageDirectory();
    String destination=temp.getAbsolutePath()+"/pictureTest/";
    Bitmap bitmap1 = BitmapFactory.decodeByteArray(data, 0, data.length);
    Matrix mat = new Matrix();
    mat.postRotate(90); // degree j'pense que t'as une methode qui te dit de combien tu veux faire t'as rotation.
    Bitmap bBitmapRotate = Bitmap.createBitmap(bitmap1, 0, 0, bitmap1.getWidth(), bitmap1.getHeight(), mat, true);
    try {
        FileOutputStream fos = null;
        finalFilePath=destination +"/" + fileName + ".jpg";
        fos = new FileOutputStream(finalFilePath);
        BufferedOutputStream bos = new BufferedOutputStream(fos);                   
        bBitmapRotate.compress(CompressFormat.JPEG, 80, bos);
        bos.flush();
        bos.close();
    } 
    catch (FileNotFoundException e) {
        e.printStackTrace();
    } 
    catch (IOException e) {
        e.printStackTrace();
    }

Funciona bien si uso una imagen de 2Mp, pero si uso una imagen de 12Mp aparece un error de falta de memoria.

    05-22 11:08:41.180: D/dalvikvm(29694): GC_FOR_MALLOC freed 674K, 51% free 3015K/6087K, external 18826K/19988K, paused 33ms
05-22 11:08:41.190: I/dalvikvm-heap(29694): Grow heap (frag case) to 25.641MB for 2070498-byte allocation
05-22 11:08:41.230: D/dalvikvm(29694): GC_CONCURRENT freed 133K, 40% free 4903K/8135K, external 17940K/19988K, paused 1ms+2ms
05-22 11:08:41.700: D/dalvikvm(29694): GC_EXTERNAL_ALLOC freed 19K, 40% free 4884K/8135K, external 33575K/35623K, paused 24ms
05-22 11:08:41.710: E/dalvikvm-heap(29694): 24000000-byte external allocation too large for this process.
05-22 11:08:41.710: E/GraphicsJNI(29694): VM won't let us allocate 24000000 bytes
05-22 11:08:41.720: D/dalvikvm(29694): GC_FOR_MALLOC freed <1K, 40% free 4884K/8135K, external 33575K/35623K, paused 14ms
05-22 11:08:41.720: D/AndroidRuntime(29694): Shutting down VM
05-22 11:08:41.720: W/dalvikvm(29694): threadid=1: thread exiting with uncaught exception (group=0x2aac8578)
05-22 11:08:41.720: E/AndroidRuntime(29694): FATAL EXCEPTION: main
05-22 11:08:41.720: E/AndroidRuntime(29694): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.graphics.Bitmap.nativeCreate(Native Method)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at com.android.cocoatweet.TestTweetPictureActivity.onPictureTaken(TestTweetPictureActivity.java:143)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.hardware.Camera$EventHandler.handleMessage(Camera.java:529)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.os.Handler.dispatchMessage(Handler.java:99)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.os.Looper.loop(Looper.java:138)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at android.app.ActivityThread.main(ActivityThread.java:3701)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at java.lang.reflect.Method.invokeNative(Native Method)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at java.lang.reflect.Method.invoke(Method.java:507)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
05-22 11:08:41.720: E/AndroidRuntime(29694):    at dalvik.system.NativeStart.main(Native Method)

Intenté configurar "setRotation ()" desde los parámetros de la cámara, pero no hizo nada.

public void onClick(View v) {
                sendPicturedTweet();
            }
        });
    }

    protected void sendPicturedTweet() {
        if(camera!=null){
            camera.stopPreview();
            Camera.Parameters camParams=this.camera.getParameters();            
            List<Size> sizes=camParams.getSupportedPictureSizes();
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
            int prefSize=Integer.parseInt(preferences.getString(getString(R.string.picture_quality_key), "0"));
            camParams.setPictureSize(sizes.get(prefSize).width, sizes.get(prefSize).height);
            camParams.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            camParams.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
            camParams.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
            camParams.setPictureFormat(ImageFormat.JPEG);
            camParams.setJpegQuality(100);
            camParams.setRotation(90);
            camera.setParameters(camParams);
            try{
                this.camera.setPreviewDisplay(surfaceHolder);
                this.camera.startPreview();
                this.camera.takePicture(null, null, null, this);
            }catch (Exception e) {
                Log.e(LOG_TAG_VIDEO_PREVIEW, "ERROR IO on set preview display for camera.");
            }
        }

    }

¿Cómo puedo rotar una imagen grande sin tener este error y tener la mejor calidad de imagen posible? ¿Es posible?

Estoy trabajando en un Sony Xperia S con Android 2.3.7.

Gracias.

preguntado el 22 de mayo de 12 a las 13:05

¿Puedo usar Renderscript para que funcione? -

4 Respuestas

Cuando llegas a esta línea

Bitmap bBitmapRotate = Bitmap.createBitmap(bitmap1, 0, 0, bitmap1.getWidth(), bitmap1.getHeight(), mat, true);

ya tienes la imagen en la memoria dos veces, como byte[] data y como Bitmap bitmap1. Creo que debería encontrar una manera de borrar los datos de byte [] antes de intentar transformar la imagen (por ejemplo, enviando directamente el mapa de bits como parámetro)

contestado el 22 de mayo de 12 a las 13:05

Gracias por su respuesta, intenté trabajar en la imagen después, pero ni siquiera puedo cargarla en un mapa de bits. - enfriador007

Reduzca el tamaño de la imagen usando BitmapFactory.Option

BitmapFactory.Options option = new BitmapFactory.Options();
            option.inSampleSize = 2;

contestado el 22 de mayo de 12 a las 14:05

Esta es una opción si no puedo encontrar una mejor manera. Necesito la mejor calidad posible y si entiendo bien esto: si reduzco el tamaño de la imagen, reduzco también la calidad. Necesito mantener la resolución de 12Mp. - enfriador007

puede usar JNI (usando el NDK) para superar la limitación del tamaño máximo de almacenamiento dinámico que Android impone a las aplicaciones.

en este caso, lo que podrías hacer es lo siguiente:

  1. pasar el mapa de bits a una función JNI.
  2. en la función JNI, lea los bytes del mapa de bits.
  3. reciclar el mapa de bits.
  4. cree un nuevo mapa de bits y coloque los píxeles que ha almacenado en él.
  5. devuelve el mapa de bits al código java.

si lo desea, he creado un código de muestra que lo hace, aquí .

contestado el 23 de mayo de 17 a las 12:05

Qué tal esto:

bitmap1 = Bitmap.createBitmap(bitmap1, 0, 0, bitmap1.getWidth(), bitmap1.getHeight(), mat, true);

Tiene una memoria limitada para usar, por lo que cuando tiene que manejar una imagen tan grande, debe pensar en guardar su memoria.

Respondido 21 ago 12, 07:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.