Używam Picassa do ładowania obrazów z Internetu w mojej aplikacji. Zauważyłem, że niektóre obrazy są wyświetlane obrócone o 90 stopni, chociaż po otwarciu obrazu w przeglądarce widzę, że jest on prawidłowo ustawiony. Zakładam, że te obrazy mają dane EXIF. Czy istnieje sposób, aby nakazać Picassoowi zignorować EXIF?Android Picasso auto obraca zdjęcie
Odpowiedz
Czy możesz opublikować obraz, którego używasz? ponieważ ta thread powiedział, że orientacja exif dla obrazów załadowanych z sieci jest ignorowana (tylko dostawca zawartości i pliki lokalne).
Próbuję również wyświetlić ten image w picasso 2.5.2, prawdziwa orientacja obrazu jest zwrócona w prawo (dolny kod na obrazie jest skierowany w prawo). Orientacja exif jest 90deg zgodnie z ruchem wskazówek zegara. Spróbuj otworzyć go w chrome (chrome honoruje rotację exif), obraz będzie skierowany w dół (dolny kod w obrazie jest skierowany w dół).
Jak wiemy, Picasso obsługuje EXIF z lokalnej pamięci masowej, odbywa się to za pośrednictwem wewnętrznych aplikacji systemu Android. Zapewnienie tej samej funkcjonalności nie może być łatwe ze względu na możliwość korzystania z niestandardowych bibliotek ładowania HTTP. Moje rozwiązanie jest proste: musimy zastąpić buforowanie i zastosować rotację Exif, zanim element zostanie zbuforowany.
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();
Tutaj dodajemy NetworkInterceptor, który może przekształcić żądanie i odpowiedź, zanim zostanie zbuforowana.
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 Transformacja
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;
}
}
Rozwiązanie to eksperymentalne i muszą być badane na szczelność i prawdopodobnie lepsza. W większości przypadków urządzenia Samsung i iOs zwracają obrót o 90 °, a to rozwiązanie działa. Inne przypadki również muszą zostać przetestowane.
- 1. Załadowane zdjęcie z iPadem obraca się
- 2. Django obraca zdjęcie iPhone po przesłaniu
- 3. ImageIO.read() zawsze obraca moje przesłane zdjęcie
- 4. RecyclerView z GridLayoutManager i Picasso pokazując niewłaściwe zdjęcie
- 5. Android - Zdjęcie przechwycone
- 6. Android Obróć zdjęcie przed zapisaniem
- 7. Android SQLite auto przyrost
- 8. Jak słuchać zdarzeń uruchomionych w Picasso (Android)?
- 9. Android: Picasso nie ładuje niektórych obrazów
- 10. Elementy wspólne systemu Android z Picasso
- 11. dodaj zdjęcie do twitter udostępnij intent android
- 12. Picasso - zmiana rozmiaru zastępczy
- 13. Android Firebase Auth - Uzyskaj zdjęcie użytkownika
- 14. Dodaj zdjęcie do Galerii multimediów - Android
- 15. Android wysłać zdjęcie i zapisać url
- 16. Android obraca mapę bitową wokół środka bez zmiany rozmiaru
- 17. 3D Navbar, który obraca się
- 18. Android Studio Picasso gif obraz ładowania dla elementu zastępczego
- 19. Picasso produkuje OutOfMemoryError
- 20. Przycinanie Picasso do widoku
- 21. OkHttp + Picasso + Retrofit
- 22. Odwołanie obrazu obciążenia Picasso
- 23. Aplikacja Android Auto nigdy nie dzwoniGetRoot
- 24. Zachowanie Realm and auto increment (Android)
- 25. Jak uzyskać gradle kompilować lokalną wersję Picasso
- 26. Zrób zdjęcie z html5
- 27. Ładowanie wielu obrazów z Picasso na tle
- 28. Czyszczenie pamięci podręcznej obrazów Picasso
- 29. Biblioteka Picasso i obrazy GridView
- 30. Picasso Załaduj obraz do celu
To dziwne. Nie zdawałem sobie sprawy, że Picasso zwrócił uwagę na EXIF. Czy masz przykładowe obrazy, które możesz połączyć? – CommonsWare
Tak. To dziwne i nieoczekiwane. Nie mogę podać mojego obecnego obrazu, ponieważ pochodzi on z prywatnego serwera. Ale po sprawdzeniu to EXIF Internecie widzę tak: Rozdzielczość: 3264 x 2448 Orientacja: obracać 90 ======= IPTC dane: ======= Więc to potwierdza, że jest EXIF odpowiedzialni za to. – Panos
Sprawdź linię # 162 https://github.com/square/picasso/blob/c8e79ce78c26e6ecdf3a0cf0a2efecd95f5ac4d7/picasso/src/main/java/com/squareup/picasso/BitmapHunter.java – Distwo