Jump to content
Unity Insider Forum

Screenshot + Größe


Kojote

Recommended Posts

Grüße!

Mal ne Frage, ich habe mir für mein Speicher und Lademenü überlegt, dass ich eine Grafikanzeige einbaue, an dem Punkt wo gespeichert wird (weißer Leerraum). Dazu wird ein Screenshot von der aktuellen Kameraansicht gemacht, dafür habe ich schon ein Script. Nun brauche ich aber nur ein kleines Bild und nicht die volle Monitorauflösung, zumal PNG ja in solchen größen eh eine zu große Dateigröße hat. Kann man beim Speichern, die Größe des Bildes beeinflussen?

HU5tYUXy.jpg

Grüße Kojote

Link zu diesem Kommentar
Auf anderen Seiten teilen

Jau, dann nimm mal die "ToTexture"-Version, damit du die Textur runterskalieren kannst (siehe Link von @Mr 3d), und dann kannst du sie selber in eine Datei speichern. Dabei hilft die Klasse ImageConversion. Die spuckt dir bytes aus, die du dann wiederum mit einem FileStream in eine Datei schreiben kannst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

OK, also ich bin eine ganze Ecke weiter gekommen, speichern funktioniert soweit:

       IEnumerator RecordSavegamePicture() {
            yield return new WaitForEndOfFrame();

            texture2D = ScreenCapture.CaptureScreenshotAsTexture();

            yield return new WaitForEndOfFrame();

            EditPicture();
        }

        private void EditPicture() {
            texture2D = ScalePictureTexture(texture2D, savegamePictureTargetWidth, savegamePictureTargetHight);
            SavePicture();
        }

        private Texture2D ScalePictureTexture(Texture2D source, int targetWidth, int targetHight) {
            Texture2D result = new Texture2D(targetWidth, targetHight, source.format, false);
            Color[] rpixels = result.GetPixels(0);
            float incX = (1.0f / (float)targetWidth);
            float incY = (1.0f / (float)targetHight);
            for (int px = 0; px < rpixels.Length; px++) {
                rpixels[px] = source.GetPixelBilinear(incX * ((float)px % targetWidth), incY * ((float)Mathf.Floor(px / targetHight)));
            }
            result.SetPixels(rpixels, 0);
            result.Apply();
            return result;
        }

        private void SavePicture() {
            // Textur in JPG und schreibbares Byte-Array Umwandeln
            byte[] byteTextureArray = texture2D.EncodeToJPG(85);

            // Dateinamen festlegen
            file = path + "/SavePicture_" + selectedSavegame + ".jpg";

            // Speichern
            FileStream fileStream = File.Open(file, FileMode.OpenOrCreate);
            fileStream.Write(byteTextureArray, 0, byteTextureArray.Length);
            fileStream.Close();
        }

Nur beim Laden harkts noch, ich kann zwar den Bytestream wieder lesen und in ein Image bringen und dann als Sprite zuweisen, aber dann ... Bekomme nur ein schwarzes Bild.

private void LoadPicturesTest() {
            for (int i = 0; i < savegamePictureSpriteArray.Length; i++) {
                file = path + "/SavePicture_1.jpg";
                if (File.Exists(file)) {
                    // Filestream öffnen und Daten in Byte-Array schreiben
                    FileStream fileStream = File.Open(file, FileMode.Open);
                    byte[] byteTextureArray = new byte[fileStream.Length];
                    fileStream.Read(byteTextureArray, 0, (int)fileStream.Length);
                    fileStream.Close();

                    // Textur aus dem Byte-Array erzeugen
                    Texture2D texture2D = new Texture2D(savegamePictureTargetWidth, savegamePictureTargetHight);
                    texture2D.LoadImage(byteTextureArray);
                    texture2D.Apply();

                    // Aus der Textur das Sprite erzeugen
                    savegamePictureSpriteArray[0] = Sprite.Create(texture2D, new Rect(0, 0, savegamePictureTargetWidth, savegamePictureTargetHight), Vector2.zero);

                    savegamePictureImage.sprite = savegamePictureSpriteArray[0];
                    Debug.Log("Erledigt!");
                }
            }
        }

EDIT:
Sehe gerade, nen Bug meldet er auch:

Assertion failed: Invalid AABB inAABB
UnityEngine.Canvas:SendWillRenderCanvases()

EDIT 2:

Super Fehler! Beim testen vergessen Länge und Breite des Bildes anzugeben, Code funktioniert wunderbar:

ut992P97.jpg

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 months later...

Hat in Unity 2017 sehr gut funktioniert. In Unity 2018 macht er dies nicht mehr.

Das kommt nach dem Skalieren heraus, vor dem Skalieren ist das Bild normal:

5450fe-1572435874.jpg

Was macht er denn hier plötzlich? 🤨

Irgendwie gibts ein paar Änderungen bei 2017 zu 2018. Mit JSON hatte ich plötzlich Probleme und mit dem Skalieren nun auch, obwohl ich an beiden Scripten nichts geändert habe.

Weiteres Problem ist, ich habe die Coroutine etwas umgebaut, dass das UI nicht mit gerendert wird:

        IEnumerator RecordSavegamePicture() {
            yield return new WaitForEndOfFrame();

            canvasGroupOverAll.alpha = 0;

            texture2D = ScreenCapture.CaptureScreenshotAsTexture();

            Debug.Log("Screen wird erstellt. Alpha ist: " + canvasGroupOverAll.alpha);

            canvasGroupOverAll.alpha = 1;

            yield return new WaitForEndOfFrame();

            EditPicture();
        }

Habe dem Canvas eine CanvasGroup verpasst und setze den Alpha vor dem Screen auf 0. Danach wieder auf 1. Aber er erstellt den Screen immer mit UI, obwohl laut Debug der Alpha 0 ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Warum skalieren? Weil du ein paar KB sparen willst? 😁 Ich speichere es einfach ab und stelle es verkleinert dar (Image). Dann geht das Speichern auch etwas schneller.

Du kannst dir ja mal dieses Asset anschauen. Ist kostenlos und hab ich mir auch gerade geholt zum testen. Scheint nice zu sein. Kannst du auch extrem hochauflösende Screenshots machen (4K, 8K, ...). https://assetstore.unity.com/packages/tools/instant-screenshot-24122

Link zu diesem Kommentar
Auf anderen Seiten teilen

Naja, ein gespeichertes Bild ist knapp über 1 MB groß. Sollte keine Probleme machen. Was jedoch jetzt immer noch nicht geht, ist das Laden der Bilddateien:

Problem war hier, dass wenn ich das Bild hiermit einlade:

private void LoadPictures() {
            for (int i = 0; i < savegamePictureSpriteArray.Length; i++) {
                file = path + "/SavePicture_" + i + ".jpg";
                if (File.Exists(file)) {
                    byte[] bytes = File.ReadAllBytes(file);
                    texture2D = new Texture2D(savegamePictureTargetWidth, savegamePictureTargetHeight, TextureFormat.RGB24, false);
                    texture2D.filterMode = FilterMode.Trilinear;
                    texture2D.LoadImage(bytes);
                    savegamePictureSpriteArray[i] = Sprite.Create(texture2D, new Rect(0, 0, savegamePictureTargetWidth, savegamePictureTargetHeight), Vector2.zero);
                    savegamePictureImage.sprite = savegamePictureSpriteArray[i];
                } else {
                    savegamePictureImage.sprite = savegamePictureEmpty;
                }
            }
        }

Ich zwar sage, dass das Image nur in einer größe von 1000 x 563 angezeigt werden soll, er aber nicht skaliert, sondern das dabei heraus kommt:

eb2f15-1572599954.jpg

Er schneidet sich ein Stückchen aus dem Bild raus zur Anzeige. Deswegen die Skalierung.

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das ist nicht skalieren was du da machst :)

Du erstellst lediglich ein neues kleineres Bild mit dem Ausschnitt eines grösseren. 

Schau dir mal Texture2D.Resize an, war aber mit dem Ergebnis nie wirklich zufrieden. Wenn du etwas recherchierst findest du auch viele Snippets die du nutzen kannst.

Aber eigentlich brauchst du das Bild ja nicht zu skalieren, du kannst es einfach im Image kleiner darstellen und wenn du ein Aspect Ratio Fitter hinzufügst, hast du alles was du brauchst :)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...