2013-04-26 2 views
1

Я нахожу в onPictureTaken, что битмап сохранен зеркально о оси y и повернут на 90 градусов по часовой стрелке, даже если предварительный просмотр камеры не был. Это на моем Nexus S, который работает 2.3.6. Эта же программа, работающая на моем Nexus 4 с 4.2, имеет результирующее растровое изображение, зеркально отраженное относительно оси Y и повернутое на 180 градусов по часовой стрелке.Как повернуть и перевернуть растровое изображение в onPictureTaken

Это код, который я бегу в onPictureTaken:

@Override 
public void onPictureTaken(final byte[] data, Camera camera) { 
    Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length); 
    String path = MediaStore.Images.Media.insertImage(getContentResolver(), picture, "name" , "description"); 
    Log.e("tag", "path: " + path); // prints something like "path: content://media/external/images/media/819" 

    try { 
     ExifInterface exif = new ExifInterface(path); // prints this error: "04-25 21:28:21.063: E/JHEAD(12201): can't open 'content://media/external/images/media/819'" 
     int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 
     Log.e("tag", "exif orientation: " + orientation); // this is outputting orientation unknown 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

Может кто-нибудь показать мне, как исправить это, учитывая, что я, кажется, получают разные результаты из разных устройств? Как определить ориентацию полученного растрового изображения так, чтобы я знал, что он поворачивает его на 90 или 180 градусов против часовой стрелки?

[EDIT]

Я добавил еще некоторую информацию, используя материал ExifInterface я читала об этом, но эта информация, кажется, не выгорело ...

+0

я думаю ExifInterface, когда я вижу это, я не уверен, просто комментарий, я никогда не использовал сырые камеры – JRowan

+0

Подождите, @JRowan так вы использовали камеру вообще? Если да, то как вы получаете растровое изображение с камеры? – user5243421

+0

onActivityResult() с новым намерением (MediaStore.ACTION_IMAGE_CAPTURE); – JRowan

ответ

12

Я поместил много работы в это и подумал, я бы поделился своим решением. Он протестирован на Motorola Devy, Samsung Xcover 1 и Samsung XCover 2.

Как я работаю с пользовательским предварительным просмотром камеры, решение в основном имеет две части . 1. Позаботьтесь о предварительном просмотре камеры и установите поворот предварительного просмотра в соответствии с на поворот устройства. 2. После того, как снимок сделан, будет вызван обратный вызов 'onPictureTaken' , поверните изображение под правильным углом, чтобы он показывал, что показывал только предварительный просмотр .


private void initPreview(int width, int height) { 
    if (camera != null && holder.getSurface() != null) { 
     try { 
      camera.setPreviewDisplay(holder); 
     } catch (Throwable t) { 
      Log.e("PreviewDemo-surfaceCallback", 
       "Exception in setPreviewDisplay()", t); 
      Toast.makeText(getContext(), t.getMessage(), 
         Toast.LENGTH_LONG).show(); 
     } 

     try { 
      Camera.Parameters parameters=camera.getParameters(); 

      Camera.Size size=getBestPreviewSize(width, height, parameters); 
      Camera.Size pictureSize=getSmallestPictureSize(parameters); 

      Display display = windowManager.getDefaultDisplay(); 
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before 
       if (isPortrait(display)) { 
        parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT); 
       } else { 
        parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE); 
       } 
      } else { // for 2.2 and later 
       switch (display.getRotation()) { 
        case Surface.ROTATION_0: // This is display orientation 
         if (size.height > size.width) parameters.setPreviewSize(size.height, size.width); 
         else parameters.setPreviewSize(size.width, size.height); 
         camera.setDisplayOrientation(90); 
         break; 
        case Surface.ROTATION_90: 
         if (size.height > size.width) parameters.setPreviewSize(size.height, size.width); 
         else parameters.setPreviewSize(size.width, size.height); 
         camera.setDisplayOrientation(0); 
         break; 
        case Surface.ROTATION_180: 
         if (size.height > size.width) parameters.setPreviewSize(size.height, size.width); 
         else parameters.setPreviewSize(size.width, size.height); 
         camera.setDisplayOrientation(270); 
         break; 
        case Surface.ROTATION_270: 
         if (size.height > size.width) parameters.setPreviewSize(size.height, size.width); 
         else parameters.setPreviewSize(size.width, size.height); 
         camera.setDisplayOrientation(180); 
         break; 
       } 
      } 

      parameters.setPictureSize(pictureSize.width, pictureSize.height); 
      //parameters.setPictureFormat(ImageFormat.JPEG); 
      camera.setParameters(parameters); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Ваш 'surfaceChanged' метод, в камере предварительного просмотра (SurfaceView), вы должны выглядеть следующим образом:


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    stopPreview(); 
    initPreview(w, h); 
    startPreview(); 
} 

где

stopPreview:

private void stopPreview() { 
    if (camera != null) { 
     camera.stopPreview(); 
    } 
} 

startPreview:

private void startPreview() { 
    if (camera != null) { 
     camera.startPreview(); 
    } 
} 

В ваш обратный вызов 'onPictureTaken' повернуть изображение, используя следующий код:

Display display = getWindowManager().getDefaultDisplay(); 
int rotation = 0; 
switch (display.getRotation()) { 
    case Surface.ROTATION_0: // This is display orientation 
    rotation = 90; 
    break; 
case Surface.ROTATION_90: 
    rotation = 0; 
    break; 
case Surface.ROTATION_180: 
    rotation = 270; 
    break; 
case Surface.ROTATION_270: 
    rotation = 180; 
     break; 
} 

Bitmap bitmap = ImageTools.toBitmap(data); 
bitmap = ImageTools.rotate(bitmap, rotation); 

BitmapTools.java

public class BitmapTools { 

    public static Bitmap toBitmap(byte[] data) { 
     return BitmapFactory.decodeByteArray(data , 0, data.length); 
    } 

    public static Bitmap rotate(Bitmap in, int angle) { 
     Matrix mat = new Matrix(); 
     mat.postRotate(angle); 
     return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true); 
    } 
} 
+1

Если вы делаете это и используете задний -facing камеры, вы должны сделать поворот на шаге 2 по-разному. – Liron

+1

Это отличный, подробный ответ. Я не использовал ваш код точно, но он определенно помог мне понять проблему, поэтому я отмечаю это как принятый ответ. Я надеюсь, что это поможет другим разработчикам, у которых есть эта проблема. – user5243421

+1

В этом ответе [link] (http://stackoverflow.com/a/26141254/1332549) объясните это лучше. – MiguelHincapieC

0

здесь вы идете проверить это , сохранить изображение и, возможно, это будет работать, и помните, если (bitmap.getWidth> bitmap.getHeight()) в качестве еще одного чека

public static int getExifRotation(String imgPath) 
    { 
     try 
     { 
      ExifInterface exif = new ExifInterface(imgPath); 
      String rotationAmount = exif.getAttribute(ExifInterface.TAG_ORIENTATION); 
      if (!TextUtils.isEmpty(rotationAmount)) 
      { 
       int rotationParam = Integer.parseInt(rotationAmount); 
       switch (rotationParam) 
       { 
        case ExifInterface.ORIENTATION_NORMAL: 
         return 0; 
        case ExifInterface.ORIENTATION_ROTATE_90: 
         return 90; 
        case ExifInterface.ORIENTATION_ROTATE_180: 
         return 180; 
        case ExifInterface.ORIENTATION_ROTATE_270: 
         return 270; 
        default: 
         return 0; 
       } 
      } 
      else 
      { 
       return 0; 
      } 
     } 
     catch (Exception ex) 
     { 
      return 0; 
     } 
    } 
+0

Мне нравится 'if (width> height)' check, но что, если другой телефон поворачивает изображение на 270 градусов? * sigh * – user5243421

+0

вы пробовали этот метод, я использую это, потому что, когда я делаю снимок, камера берет его и поворачивает на 90 градусов, как его сохраняют, но когда отображается в галерее или как он отображается, как я сделал снимок, поэтому открывая его программно, я чтобы проверить, как это – JRowan

+0

, и я использую matrix.preRotate() или matrix.postRotate() с Bitmap.createBitmap() после проверки в зависимости от – JRowan

0

вы должны прочитать о ExifInterface, чтобы решить эту проблему.

У меня есть эта функция в моем приложении для проверки изображения погоды, взятого с камеры, необходимо вращать или нет.

 if(ExifNeedsRotate(GetPathFromUri(context, selectedImage))){ 
    // Rotate your bitmap using the Matrix 
    } 


public static boolean ExifNeedsRotate(String paramString){ 

     if (android.os.Build.VERSION.SDK_INT >= 5){ 

      try 
      { 

       Class localClass = Class.forName("android.media.ExifInterface"); 
       Class[] arrayOfClass1 = new Class[1]; 
       arrayOfClass1[0] = String.class; 
       Constructor localConstructor = localClass.getConstructor(arrayOfClass1); 
       Class[] arrayOfClass2 = new Class[1]; 
       arrayOfClass2[0] = String.class; 
       Method localMethod = localClass.getMethod("getAttribute", arrayOfClass2); 
       Object[] arrayOfObject1 = new Object[1]; 
       arrayOfObject1[0] = paramString; 
       Object localObject1 = localConstructor.newInstance(arrayOfObject1); 
       Object[] arrayOfObject2 = new Object[1]; 
       arrayOfObject2[0] = "Orientation"; 
       Object localObject2 = localMethod.invoke(localObject1, arrayOfObject2); 
       if (localObject2 != null){ 
         boolean bool = localObject2.equals("6"); 
         if (bool) 
         return true; 
       } 

      } 
      catch (Exception localException){ 
       return false; 
      } 

    } 

    return false; 

} 

Проложить путь к ImageUri в качестве входного сигнала.

public static String GetPathFromUri(Context paramContext, Uri paramUri) 
    { 
     String str; 
     try 
     { 
      if (paramUri.toString().startsWith("file:")){ 
        str = paramUri.getPath(); 
      } 
      else 
      { 
        str = null; 
        String[] arrayOfString = new String[1]; 
        arrayOfString[0] = "_data"; 
        Cursor localCursor = paramContext.getContentResolver().query(paramUri, arrayOfString, null, null, null); 
        if (localCursor != null) 
        { 
          localCursor.moveToFirst(); 
          int i = localCursor.getColumnIndex(arrayOfString[0]); 
          if ((localCursor.getCount() >= 1) && (localCursor.getColumnCount() >= i + 1)) 
           str = localCursor.getString(i); 
          localCursor.close(); 
        } 
      } 

     } 
     catch (Exception localException){ 
      str = null; 
     } 

     return str; 
    } 
Смежные вопросы