Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?

Dies ist nicht eine einfache problem, bitte Lesen!

Möchte ich Bearbeiten einer JPEG-Datei und speichern Sie es wieder als JPEG. Das problem ist, dass auch ohne manipulation gibt es signifikante (sichtbaren) Qualitätsverlust.
Frage: welche option oder API bin ich in der Lage sein zu re-compress JPEG-ohne Qualitätsverlust (ich weiß es nicht genau, aber ich denke, was ich weiter unten beschreiben ist nicht eine akzeptable Artefakte, vor allem mit Qualität=100).

Kontrolle

Lade ich es als Bitmap aus der Datei:

BitmapFactory.Options options = new BitmapFactory.Options();
//explicitly state everything so the configuration is clear
options.inPreferredConfig = Config.ARGB_8888;
options.inDither = false; //shouldn't be used anyway since 8888 can store HQ pixels
options.inScaled = false;
options.inPremultiplied = false; //no alpha, but disable explicitly
options.inSampleSize = 1; //make sure pixels are 1:1
options.inPreferQualityOverSpeed = true; //doesn't make a difference
//I'm loading the highest possible quality without any scaling/sizing/manipulation
Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/image.jpg", options);

Nun, eine Steuerung Bild zu vergleichen, zu speichern Sie nun die Ebene bytes Bitmap als PNG:

bitmap.compress(PNG, 100/*ignored*/, new FileOutputStream("/sdcard/image.png"));

Ich diese im Vergleich zu den original-JPEG-Bild auf meinem computer und es gibt keinen visuellen Unterschied.

Ich auch so gespeichert, raw - int[] aus getPixels geladen und es wie ein rohes ARGB-Datei auf meinem computer: es gibt keinen visuellen Unterschied zum original-JPEG noch PNG gespeichert von Bitmap.

Überprüfte ich die Bitmap mit den Abmessungen und der Konfiguration, die Sie mit die Quelle Bild und die Eingabe-Optionen: es decodiert werden, wie ARGB_8888 als erwartet.

Den obigen Kontrollen beweisen, dass die Pixel in der in-memory Bitmap korrekt sind.

Problem

Möchte ich JPEG-Dateien als Ergebnis, so dass die oben genannten PNG-und RAW-Ansätze nicht funktionieren würde, lassen Sie uns versuchen zu speichern als JPEG 100% erste:

//100% still expected lossy, but not this amount of artifacts
bitmap.compress(JPEG, 100, new FileOutputStream("/sdcard/image.jpg"));

Ich bin nicht sicher, ob seine Maßnahme ist Prozent, aber es ist einfacher zu Lesen und zu diskutieren, also werde ich es verwenden.

Ich bin mir bewusst, dass JPEG mit der Qualität von 100% ist immer noch verlustbehaftet, aber es sollte nicht so visuell verlustbehaftet, es fällt aus der Ferne. Hier ist ein Vergleich von zwei 100% Kompressionen der gleichen Quelle.

Öffnen Sie Sie in separaten Registerkarten und klicken Sie auf hin und her zwischen zu sehen, was ich meine. Der Unterschied Bilder wurden mit Gimp: original als untere Schicht, re-komprimiert-Mittelschicht mit "Grain extract" - Modus, top-layer, full white mit "Wert" - Modus zur Verbesserung der Schlechtigkeit.

Die folgenden Bilder sind hochgeladen auf Imgur, die auch komprimiert die Dateien, aber da die Bilder sind alle komprimiert die gleiche, die ursprüngliche unerwünschte Artefakte sichtbar bleiben, so wie ich es sehen, beim öffnen von meinem ursprünglichen Dateien.

Original [560k]:
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?
Imgur ist der Unterschied zum original - (nicht relevant für das problem, nur um zu zeigen, dass es nicht verursacht extra Artefakte beim hochladen der Bilder):
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?
IrfanView 100% [728k] (optisch identisch zum original):
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?
IrfanView 100%'en Unterschied zum original (kaum etwas)
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?
Android 100% [942k]:
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?
Android 100%'en Unterschied zum original (Tönung, banding, schmieren)
Wie zu komprimieren Bitmap als JPEG mit der geringsten Qualitätsverlust auf Android?

IrfanView habe ich zu gehen, unter 50% [50k], um zu sehen, aus der Ferne ähnliche Effekte. Bei 70% [100k] in IrfanView gibt es keinen merklichen Unterschied, aber die Größe ist 9. Android.

Hintergrund

Erstellte ich eine app, die ein Bild von der Kamera-API, das Bild kommt als byte[] und ist eine kodierte JPEG-blob. Ich speicherte diese Datei per OutputStream.write(byte[]) Methode, das war meine ursprüngliche Quelldatei. decodeByteArray(data, 0, data.length, options) dekodiert die gleichen Pixel wie das Lesen aus einer Datei, getestet mit Bitmap.sameAs es ist also irrelevant für das Problem.

War ich mit meinem Samsung Galaxy S4 mit Android 4.4.2 Dinge testen.
Edit: während der Untersuchung weiter ich habe auch versucht Android 6.0 und N Album Vorhören Emulatoren und Sie reproduzieren das gleiche Problem.

Wenn Sie nicht wie die Android-JPEG-codec, du bist frei, Ihre eigenen mitbringen. Ich denke nicht, dass eine Menge von Nötigung machen Android tun, was Sie wollen, die Art und Weise, die Sie Messen.
Vereinbart. AFAIK, "es ist was es ist" hier. Je nach den Manipulationen, die Sie tun möchten, könnten Sie nicht tun es in Java sowieso, aufgrund Speicher Einschränkungen, greifen Sie stattdessen auf die NDK. In diesem Fall, das Verhalten der Bitmap.compress() werden, fraglich. Epic Analyse, aber! 🙂
die "Manipulationen" ich will tun, ist so einfach wie das zuschneiden einen Teil des Bildes, aber das bedeutet, dass ich zu re-codieren; und das will JPEG durch Speicherplatz betrifft. Hast du irgendwelche hintergrund auf, warum Android gehen würde mit einem sub-par-Implementierung des JPEG?
was ist Ihr Vorschlag? (auch in form einer Antwort 😉 ich weiß nicht wirklich umsetzen wollen, meine eigene encoder, aber es wäre schön, eine alternative haben. Meine Messung ist rein visuell und empirisch: ich habe eine Menge Bilder, wo das wirklich sichtbar ist, kann die oben nicht das beste Beispiel, aber ich denke, es ist ausreichend, um den Punkt durch.
Bitmap.compress() gewesen wäre, die ursprünglich für single-core, ~500MHz CPUs und 192MB Gerät RAM. Das ist in etwa auf Augenhöhe mit 15-Jahr-alten PCs. Also, es war optimiert für geringe CPU-und low-RAM, nicht die max Qualität. Ich habe keine Ahnung, ob Sie es verbessert im Laufe der Zeit oder nicht, da dieses Gerät die Anforderungen wurden klettern. "Ich habe eine Menge Bilder, wo das wirklich sichtbar" -- beachten Sie, dass Sie möglicherweise empfindlicher auf die Frage, als andere. Ich bin notorisch miserabel, und wenn ich starre auf die Fotos, werde ich erkennen, minimale Unterschiede, aber das ist es.

InformationsquelleAutor TWiStErRob | 2016-04-07

Schreibe einen Kommentar