Создание / загрузка миниатюры скриншота

Миниатюру снимка экрана можно использовать в различных ситуациях, например, как иконку текущего уровня, когда игрок покинул его и вышел в меню. Еще, миниатюра скриншота будет полезна, в системе сохранения игры, где создается файл игровых данных и рядом с ним миниатюра с точно таким же именем, затем, в игровом меню при выборе сохранения, будет показываться мини скриншот. В общем, штука полезная, осталось только разобраться как из скриншота сделать миниатюру, и как загружать эти файлы изображений в дальнейшем. Давайте разберемся с этими вопросами на примере ниже.

Для начала, добавим на сцену сам скрипт:

using System.Collections;
using UnityEngine.UI;
using UnityEngine;
using System.IO;

public class TakeThumbnail : MonoBehaviour {

	private static TakeThumbnail instance;

	void Awake()
	{
		instance = this;
	}

	public static void Generate(string path, Canvas[] ignoreCanvas, float scale)
	{
		if(string.IsNullOrEmpty(path)) return;
		scale = Mathf.Clamp(scale, .1f, 1f);
		instance.GenerateThumbnail(path, ignoreCanvas, scale);
	}

	void GenerateThumbnail(string path, Canvas[] ignoreCanvas, float scale)
	{
		StartCoroutine(Thumbnail(path, ignoreCanvas, scale));
	}

	IEnumerator Thumbnail(string path, Canvas[] ignoreCanvas, float scale)
	{
		yield return null;

		if(ignoreCanvas != null)
		for(int i = 0; i < ignoreCanvas.Length; i++) ignoreCanvas[i].enabled = false;

		yield return new WaitForEndOfFrame();

		Texture2D result = null;
		Texture2D tex = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
		tex.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
		tex.Apply();

		if(ignoreCanvas != null)
		for(int i = 0; i < ignoreCanvas.Length; i++) ignoreCanvas[i].enabled = true;
		
		int width = (int)(Screen.width * scale);
		int height = (int)(Screen.height * scale);

		if(scale < 1)
		{
			result = new Texture2D(width, height, tex.format, true);
			Color[] pixels = result.GetPixels(0);

			float x = ((float)1 / tex.width) * ((float)tex.width / width);
			float y = ((float)1 / tex.height) * ((float)tex.height / height);

			for(int i = 0; i < pixels.Length; i++)
			{
				pixels[i] = tex.GetPixelBilinear(x * ((float)i % width), y * ((float)Mathf.Floor(i / width)));
			}

			result.SetPixels(pixels, 0);
			result.Apply();
		}
		else
		{
			result = tex;
		}



		byte[] bytes = result.EncodeToPNG();
		File.WriteAllBytes(path, bytes);

		Debug.Log(this + " --> Создано изображение (" + width + "x" + height + ") по адресу: " + path);

		if(tex != null) Destroy(tex);
		if(result != null) Destroy(result);
	}

	public static Texture2D LoadTexture2D(string path)
	{
		if(!File.Exists(path)) return null;
		byte[] data = File.ReadAllBytes(path);
		Texture2D result = new Texture2D(2, 2);
		result.LoadImage(data);
		return result;
	}

	public static Sprite LoadSprite(string path)
	{
		if(!File.Exists(path)) return null;
		byte[] data = File.ReadAllBytes(path);
		Texture2D tex = new Texture2D(2, 2);
		tex.LoadImage(data);
		return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100);
	}
}

Скрипт по сути создает обычный скриншот, подобных скриптов множество, но тут есть небольшое отличие, которое заклюается в том, что создается еще одна текстура, просто меньшего размера. Здесь можно делать как полноразмерные скриншоты, так и миниатюры.

Метод Generate имеет три переменные: string path, Canvas[] ignoreCanvas, float scale.

path - указываем путь к файлу, вместе с его разрешением PNG.
ignoreCanvas - массив Canvas, это если мы хотим скрин без UI (прицел, здоровье, жизни и т.п.).
scale - размер миниатюры в процентах, значения 0.1f...1f, что значит от 10% и до 100%.

Примеры использования:

public Image img;
public MeshRenderer mesh;
public Canvas[] ignoreCanvas;

void Exemple()
{
	// загрузить как текстуру
	mesh.material.mainTexture = TakeThumbnail.LoadTexture2D(Application.persistentDataPath + "/img.png");

	// загрузить как спрайт
	img.sprite = TakeThumbnail.LoadSprite(Application.persistentDataPath + "/img.png");

	// создать миниатюру вместе с UI элементами
	TakeThumbnail.Generate(Application.persistentDataPath + "/img.png", null, 0.5f);

	// создать миниатюру без указанных UI групп
	TakeThumbnail.Generate(Application.persistentDataPath + "/img.png", ignoreCanvas, 0.5f);
}


Скачать скрипт:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 2017.3.0

Комментариев 2

Офлайн
Frejk 9 февраля 2018
по защите приложения уроки будут?
Офлайн
Light 9 февраля 2018
Frejk, что именно защищать? Если игра сетевая, то защита должна быть на сервере. Для локальной игры не вижу смысла изобретать изощренные способы шифрования сейвов или памяти, если игрок решил накрутить себе золота или жизней, то это его дело. Нужно не забывать что все эти меры шифрования и дешифрования, потребуют более мощного железа.

Но защитить исходный код приложения можно. Для этого нужны специальные плагины, есть бесплатные, например: https://assetstore.unity.com/packages/tools/utilities/obfuscator-free-89420
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика