Android Picasso自动旋转图像

我正在使用毕加索从我的应用程序中的网站加载图像。 我注意到,有些图像显示旋转了90度,虽然当我在浏览器中打开图像,我看到它正确定位。 我假设这些图像有EXIF数据。 有没有办法指示毕加索忽略EXIF?

Solutions Collecting From Web of "Android Picasso自动旋转图像"

我们知道,毕加索支持本地存储的EXIF,这是通过Android内部的Utils来完成的。 由于能够使用自定义的Http加载库,提供相同的function是不容易的。 我的解决scheme很简单:在caching项目之前,我们必须重写caching并应用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,它可以在请求和响应被caching之前转换。

 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; } } 

这个解决scheme是实验性的,必须经过泄漏testing,可能会有所改进。 在大多数情况下,三星和iOs设备返回90°旋转,这种解决scheme的工作。 其他情况也必须进行testing。

你可以发布你正在使用的图像? 因为正如这个线程所说的那样,从Web上加载的图像的Exif方向被忽略(只有内容提供者和本地文件)。

我也尝试在picasso 2.5.2中显示这个图像 , 图像的真实方向正面临着版权(图像底部的代码是正确的)。 exif方向是顺时针90度。 尝试在Chrome中打开它(铬是表示exif旋转),图像将面朝下(图像底部的代码是朝下)。