Um einen Screenshot einer View
zu erzeugen, wird gemeinhin empfohlen, den Drawing Cache der View zu missbrauchen, indem man ihn gegebenenfalls erzwingt und dann kopiert:
public class LameFooView extends SurfaceView { @NotNull public final Bitmap getScreenCopy() { boolean cacheEnabled = isDrawingCacheEnabled(); if (!cacheEnabled) buildDrawingCache(); Bitmap cache = getDrawingCache(); // <-- there be dragons Bitmap screenshot = new Bitmap(cache); // destroy the cache if it wasn't enabled, then return if(!cacheEnabled) destroyDrawingCache(); return screenshot; } }
Aus Gründen purer Gehässigkeit lieferte der Aufruf von getDrawingCache()
in meiner vererbten SurvaceView
allerdings immer null
, womit die ganze Aktion gestorben war.
Faszinierenderweise funktionierte stattdessen der Ansatz, die View
erneut auf eine eigene Bitmap
zu rendern, indem man der eigenen draw()
-Methode ein raubkopiertes Canvas
übergibt:
public class AwesomeFooView extends SurfaceView { @NotNull public final Bitmap getScreenCopy() { Bitmap bitmap = Bitmap.createBitmap( getWidth(), getHeight(), Bitmap.Config.ARGB_8888 ); Canvas temporaryCanvas = new Canvas(bitmap); draw(temporaryCanvas); // Voodoo. return bitmap; } }
Wer also vor einem ähnlichen Problem steht — so geht es auch.
Pro-Tipp
Wie der Dokumentation von View.draw()
zu entnehmen ist, muss die View zum Zeitpunkt des Abpausens bereits den Layout-Durchgang durchlaufen haben. Dies lässt sich mit einem gewissenhaften Aufruf von View.layout()
erzwingen:
measure(getWidth(), getHeight()); layout(0, 0, getWidth(), getHeight());
Problem gelöst.
Guten Morgen!
Ich bin bereits seit zwei Tagen nach einer Lösung, um einen Screenshot von einer SurfaceView zu machen, in der die Camera Preview angezeigt wird. Meine SurfaceView habe ich in meiner main.xml angelegt.
Ich habe gelesen, dass es scheinbar nicht möglich sein soll, von der SurfaceView einen Screenshot zu machen, aber wenn ich auf meinem Android Endgerät mit dem Handballen über das Display fahre, so erhalte ich ja auch einen Screenshot.
Hast Du ggf. eine Idee, wie ich das programmatisch umsetzen könnte? Ich verzweifel so langsam daran.
Ich benötige es, um ein Image von der Camera und diverser Overlays zu erhalten. Die Camera API bringt mich da nicht weiter.
Derzeit nehme ich ein Foto über die Camera API auf und erstelle gleichzeitig einen Screenshot der Overly Elemente und füge diese dann mittel Canvas zusammen um sie dann als ein Bild zu speichern.…seeeehr langsam bzw. sehr Resourcenagressiv 🙁
Wäre super, wenn Du einen Tipp hättest.
Danke und Grüße Jochen
Hallo Jochen,
hast du mittlerweile eine Lösung für das Problem gefunden?
Ich habe nämlich genau das gleiche Problem und komme gerade auch nicht wirklich weiter.
Wäre eine große Hilfe.
Danke
Hallo,
ja ich habe bereits eine Lösung gefunden. Man muss die onPreviewFrame überschreiben und über YUV420 verwenden.
Die onPreviewFrame überschreibe ich einfach in meiner onClick(View v) wenn ich die Camera Preview aktiviere:
Zusätzlich musst Du dann auch noch decodeYUV420SP definieren. Das habe ich direkt unter der onClick() gemacht:
Und meine Screenshots speichere ich so ab:
Wobei ich mScreenshotPath vorab definiert habe:
Der Ordner MeineBilder muss natürlich auch noch existieren:
Meine SurfaceView habe mittels XML hinzugefügt in diesem Fall, aber ich glaube das spielt keine Rolle.
Ich hoffe ich konnte Dir weiter helfen 😉
Grüße Jochen