2015-01-13 42 views
17

Picasaを使用してアプリケーションのWebから画像を読み込みます。私はいくつかの画像が90度回転して表示されていることに気がつきましたが、ブラウザで画像を開くと、正しく配置されています。私はこれらの画像がEXIFデータを持っていると仮定します。ピカソにEXIFを無視するよう指示する方法はありますか?Android Picasso auto rotate image

+0

これは奇妙です。私はピカソがEXIFに注意を払ったことに気付かなかった。リンクできるサンプル画像がありますか? – CommonsWare

+0

はい。奇妙で予想もしません。私は私の現在のイメージを私的なサーバから来るように伝えることはできません。 解像度:X 2448 3264 オリエンテーション:90 ======= IPTCデータを回転させる:======= だから、EXIFであることを確認されているが、確認した後に、それは私がこれを見るオンラインEXIFですその責任を負います。 – Panos

+1

チェックライン#162 https://github.com/square/picasso/blob/c8e79ce78c26e6ecdf3a0cf0a2efecd95f5ac4d7/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java – Distwo

答えて

0

使用している画像を投稿できますか? threadによると、Webから読み込まれた画像のexif方向は無視されます(コンテンツプロバイダとローカルファイルのみ)。

また、このimageをpicasso 2.5.2に表示しようとすると、画像の実際の向きが右側に向いています(画像の下のコードが右向きです)。 exifの方向は時計回りに90degです。クロムで開いてみてください(クロムはexifの回転を尊重しています)、画像がフェイスダウンされます(画像の下のコードが下になる)。

2

私が知っているように、PicassoはローカルストレージからEXIFをサポートしています。これはAndroid inner Utilsを介して行われます。同じ機能を提供することは、カスタムHTTP読み込みライブラリを使用する能力のために簡単に行うことはできません。 私のソリューションは簡単です:アイテムをキャッシュする前にキャッシュをオーバーライドしてExifローテーションを適用する必要があります。

OkHttpClient client = new OkHttpClient.Builder() 
     .addNetworkInterceptor(chain -> { 
      Response originalResponse = chain.proceed(chain.request()); 
      byte[] body = originalResponse.body().bytes(); 
      ResponseBody newBody = ResponseBody 
       .create(originalResponse.body().contentType(), ImageUtils.processImage(body)); 
      return originalResponse.newBuilder().body(newBody).build(); 
     }) 
     .cache(cache) 
     .build(); 

は、ここではそれがキャッシュされる前に、要求と応答を変換することができNetworkInterceptorを追加します。

public class ImageUtils { 

    public static byte[] processImage(byte[] originalImg) { 
     int orientation = Exif.getOrientation(originalImg); 
     if (orientation != 0) { 
      Bitmap bmp = BitmapFactory.decodeByteArray(originalImg, 0, originalImg.length); 
      ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
      rotateImage(orientation, bmp).compress(Bitmap.CompressFormat.PNG, 100, stream); 

      return stream.toByteArray(); 
     } 
     return originalImg; 
    } 

    private static Bitmap rotateImage(int angle, Bitmap bitmapSrc) { 
     Matrix matrix = new Matrix(); 
     matrix.postRotate(angle); 
     return Bitmap.createBitmap(bitmapSrc, 0, 0, 
       bitmapSrc.getWidth(), bitmapSrc.getHeight(), matrix, true); 
    } 
} 

のExif変換:

public class Exif { 
    private static final String TAG = "Exif"; 

    // Returns the degrees in clockwise. Values are 0, 90, 180, or 270. 
    public static int getOrientation(byte[] jpeg) { 
     if (jpeg == null) { 
      return 0; 
     } 

     int offset = 0; 
     int length = 0; 

     // ISO/IEC 10918-1:1993(E) 
     while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) { 
      int marker = jpeg[offset] & 0xFF; 

      // Check if the marker is a padding. 
      if (marker == 0xFF) { 
       continue; 
      } 
      offset++; 

      // Check if the marker is SOI or TEM. 
      if (marker == 0xD8 || marker == 0x01) { 
       continue; 
      } 
      // Check if the marker is EOI or SOS. 
      if (marker == 0xD9 || marker == 0xDA) { 
       break; 
      } 

      // Get the length and check if it is reasonable. 
      length = pack(jpeg, offset, 2, false); 
      if (length < 2 || offset + length > jpeg.length) { 
       Log.e(TAG, "Invalid length"); 
       return 0; 
      } 

      // Break if the marker is EXIF in APP1. 
      if (marker == 0xE1 && length >= 8 && 
        pack(jpeg, offset + 2, 4, false) == 0x45786966 && 
        pack(jpeg, offset + 6, 2, false) == 0) { 
       offset += 8; 
       length -= 8; 
       break; 
      } 

      // Skip other markers. 
      offset += length; 
      length = 0; 
     } 

     // JEITA CP-3451 Exif Version 2.2 
     if (length > 8) { 
      // Identify the byte order. 
      int tag = pack(jpeg, offset, 4, false); 
      if (tag != 0x49492A00 && tag != 0x4D4D002A) { 
       Log.e(TAG, "Invalid byte order"); 
       return 0; 
      } 
      boolean littleEndian = (tag == 0x49492A00); 

      // Get the offset and check if it is reasonable. 
      int count = pack(jpeg, offset + 4, 4, littleEndian) + 2; 
      if (count < 10 || count > length) { 
       Log.e(TAG, "Invalid offset"); 
       return 0; 
      } 
      offset += count; 
      length -= count; 

      // Get the count and go through all the elements. 
      count = pack(jpeg, offset - 2, 2, littleEndian); 
      while (count-- > 0 && length >= 12) { 
       // Get the tag and check if it is orientation. 
       tag = pack(jpeg, offset, 2, littleEndian); 
       if (tag == 0x0112) { 
        // We do not really care about type and count, do we? 
        int orientation = pack(jpeg, offset + 8, 2, littleEndian); 
        switch (orientation) { 
         case 1: 
          return 0; 
         case 3: 
          return 180; 
         case 6: 
          return 90; 
         case 8: 
          return 270; 
        } 
        Log.i(TAG, "Unsupported orientation"); 
        return 0; 
       } 
       offset += 12; 
       length -= 12; 
      } 
     } 

     Log.i(TAG, "Orientation not found"); 
     return 0; 
    } 

    private static int pack(byte[] bytes, int offset, int length, 
          boolean littleEndian) { 
     int step = 1; 
     if (littleEndian) { 
      offset += length - 1; 
      step = -1; 
     } 

     int value = 0; 
     while (length-- > 0) { 
      value = (value << 8) | (bytes[offset] & 0xFF); 
      offset += step; 
     } 
     return value; 
    } 
} 

このソリューションは、実験的であると漏れをテストし、おそらく改善されなければなりません。ほとんどの場合、SamsungおよびiOsデバイスは90°回転し、このソリューションが機能します。他のケースもテストする必要があります。