Bild ohne OutOfMemory zuschneiden - Android

8

Ich möchte das Bild zuschneiden, ohne dass OutOfMemory exception angezeigt wird.
es bedeutet, dass ich x, y, Breite und Höhe des beschnittenen Bildes habe und das ursprüngliche Bild beschneiden möchte, ohne es in den Speicher zu bringen Ja, ich weiß, dass BitmapRegionDecoder eine gute Idee ist, aber vielleicht wäre das beschnittene Bild zu groß, um es in den Speicher zu bringen.

Eigentlich möchte ich keine kopierte Bitmap, sondern nur beschnittenes Bild von der Quelldatei in die Zieldatei schreiben.


BEARBEITEN: Ich möchte speichern beschnittenes Bild nicht nur in ImageView anzeigen Ich möchte es in einer neuen Datei speichern ohne Dimensionen zu verlieren

Dies ist das Beispiel

in dieser Situation abgeschnitten Bildauflösung ist 20000x20000 und Code unten funktioniert nicht Ursache von OOM:

%Vor%

mit inSampleSize, um die ursprüngliche Bildgröße zu verringern, ist gut, aber das Ergebnis, das ich speichere, ist nicht mehr 20000x20000.

Wie kann ich den 25000x25000 beschneiden und den 20000x20000 Bildteil in einer Datei speichern?

    
Sepehr Behroozi 27.12.2015, 11:58
quelle

4 Antworten

1

Einfach gesagt, es erfordert viele Low-Level-Programmierung und Optimierungen.

Wie Sie sehen können, weisen viele Antworten in dieser Region auf generische Konzepte der Bitmap-Komprimierung usw. hin, die in den meisten Ausgaben, aber nicht speziell in Ihren Fragen anwendbar sind.

Auch BitmapRegionDecoder, wie in Antworten vorgeschlagen, wird nicht gut funktionieren. Es sicher verhindert das Laden der gesamten Bitmap im RAM, aber was ist mit dem beschnittenen Bild? Nach dem Beschneiden eines Bildes erhalten Sie eine riesige Bitmap, die Ihnen, egal was, ein OOM gibt.

Weil Ihr Problem, wie Sie es beschrieben haben, Bitmaps benötigt, um geschrieben oder von der Platte gelesen zu werden, wenn sie geschrieben oder aus dem Speicher gelesen werden; etwas, das als BufferedBitmap (oder so ähnlich) bezeichnet wird, das den benötigten Speicher effizient verarbeitet, indem kleine Teile einer Bitmap auf Platte gespeichert und später verwendet werden, wodurch OOM vermieden wird.

Jede andere Lösung, die das Problem mit der Skalierung lösen will, macht nur die Hälfte der Arbeit. Warum? weil das beschnittene Bild selbst zu groß für den Speicher sein kann (wie Sie gesagt haben).

Allerdings ist es nicht so schlimm, das Problem durch Skalierung zu lösen, wenn Sie die Qualität des zugeschnittenen Bildes nicht im Vergleich zu der Qualität, die der Benutzer beim Beschneiden gesehen hat, interessieren. das ist, was die Google Fotos tun, es reduziert einfach die Qualität des beschnittenen Bildes, sehr einfach!

Ich habe noch keine BufferedBitmap-Klassen gesehen (aber wenn es welche gäbe, wäre das großartig). Sie werden sicher nützlich für die Lösung ähnlicher Probleme.

Sie können die Telegramm-Messaging-App überprüfen, die mit einer Open-Source-Implementierung von Bildbeschneidungsmöglichkeiten geliefert wird. Sie raten richtig, es handhabt alle ähnlichen bösen Arbeiten mit gutem altem C ... folglich können wir schlussfolgern, dass eine gute globale Lösung (oder besser gesagt, EINE DER VERSCHIEDENEN ANWENDBAREN LÖSUNGEN) scheint, Low-level Programmieren zu sein, um Diskette zu behandeln und speicher dich selbst.

Ich weiß, dass meine Antwort keine Kopie-Paste-ische Lösung für Ihr Problem geben konnte, aber ich hoffe zumindest, dass es Ihnen einige Ideen gegeben hat, mein Freund.

    
Dusk 03.01.2016, 10:21
quelle
1

Haben Sie BitmapRegionDecoder überprüft? Es wird ein Rechteck aus dem Originalbild extrahiert.

%Vor%

Ссылка

    
Ankit Aggarwal 30.12.2015 12:06
quelle
1

Sie können dies mithilfe von BitmapFactory lösen. Um die ursprüngliche Bitmap-Größe zu bestimmen, ohne sie in den Speicher zu legen, führen Sie den folgenden Befehl aus:

%Vor%

Jetzt können Sie options.inSampleSize

verwenden
  

Wenn auf einen Wert & gt; 1, fordert den Decoder an   Subsample das Originalbild, ein kleineres Bild zum Speichern zurück   Erinnerung. Die Stichprobengröße ist die Anzahl der Pixel in jeder Dimension   das entspricht einem einzelnen Pixel in der decodierten Bitmap. Beispielsweise,   inSampleSize == 4 gibt ein Bild zurück, das 1/4 der Breite / Höhe von   Original und 1/16 der Anzahl der Pixel. Jeder Wert & lt; = 1 wird behandelt   wie 1. Hinweis: Der Decoder verwendet einen Endwert basierend auf Potenzen von 2,   jeder andere Wert wird auf die nächste Potenz von 2 abgerundet.

Jetzt ist es keine perfekte Lösung, aber Sie können Mathe machen, um den nächsten Faktor von 2 zu finden, den Sie in options.inSampleSize verwenden können, um Speicher zu sparen.

%Vor%     
Ilya Gazman 30.12.2015 12:30
quelle
0

BitmapRegionDecoder eignet sich zum Zuschneiden von großen oder großen Bildern, ist aber ab API 10 verfügbar.

Es gibt eine Klasse namens BitmapRegionDecoder, die Ihnen helfen kann, aber ab API 10 verfügbar ist.

Wenn Sie es nicht verwenden können:

Viele Bildformate sind komprimiert und erfordern daher eine Art Laden in den Speicher.

Sie müssen über das beste Bildformat lesen, das Ihren Anforderungen entspricht, und es dann selbst lesen, indem Sie nur den Speicher verwenden, den Sie brauchen.

Eine etwas einfachere Aufgabe wäre es, alles in JNI zu machen, so dass, obwohl Sie viel Speicher verwenden werden, zumindest Ihre App nicht so bald in OOM kommen wird, da sie nicht auf das Maximum beschränkt ist Heap-Größe, die für normale Apps gilt.

Natürlich, da Android Open Source ist, können Sie versuchen, den BitmapRegionDecoder zu verwenden und ihn für jedes Gerät zu benutzen.

Referenz: Bild ohne Laden in den Speicher zuschneiden

Oder Sie finden unten einen anderen Weg, der für Sie hilfreich sein könnte:

Bitmap / Canvas-Verwendung und das NDK

    
KishuDroid 02.01.2016 07:09
quelle

Tags und Links