using System; using System.IO; using QRCoder; using RR.Common.Prizes; using UnityEngine; using UnityEngine.Serialization; using Color = System.Drawing.Color; namespace RR.Common.Utility { /// /// Утилитарный класс для создания QR-кодов в Unity. /// Предоставляет статические методы для генерации QR-кодов в виде текстур. /// public class QRMaker : MonoBehaviour { /// /// Создает текстуру QR-кода из переданного текста. /// /// Текст или данные для кодирования в QR-код. /// Количество пикселей на один модуль QR-кода. По умолчанию 8. /// Определяет, нужно ли рисовать тихие зоны (белые поля) вокруг QR-кода. По умолчанию true. /// Темный цвет в QR-коде /// Светлый цвет в QR-коде /// Texture2D с изображением QR-кода, готовая для использования в UI или материалах. public static Texture2D MakeTexture(string text, int pixelsPerModule = 8, bool drawQuietZones = true, Color darkColor = default, Color lightColor = default) { Color dark = darkColor == default ? Color.Black : darkColor; Color light = lightColor == default ? Color.White : lightColor; QRCodeGenerator gen = new(); QRCoder.QRCodeData data = gen.CreateQrCode(text, QRCodeGenerator.ECCLevel.M); PngByteQRCode png = new(data); // Генерим PNG-байты с указанными цветами byte[] bytes = png.GetGraphic(pixelsPerModule, dark, light, drawQuietZones); Texture2D tex = new(150, 150, TextureFormat.RGBA32, false); tex.LoadImage(bytes); // раскодирует PNG → RGBA tex.Apply(false, false); return tex; } // public static Texture2D MakeTexture(string text, Image icon = null, int pixelsPerModule = 8, // bool drawQuietZones = true) // { // QRCodeGenerator gen = new(); // QRCoder.QRCodeData data = gen.CreateQrCode(text, QRCodeGenerator.ECCLevel.M); // QRCode code = new(data); // Bitmap bitmapIcon = code.GetGraphic(pixelsPerModule, // Color.Black, // Color.White, // icon == null ? null : new Bitmap(icon), // 15, // 10, // drawQuietZones); // Texture2D tex = new(150, 150, TextureFormat.RGBA32, false); // tex.LoadImage(bitmapIcon); // } // Сохранить как PNG-файл public static string SavePng(string text, string filePath, int ppm = 8) { QRCodeGenerator gen = new(); QRCoder.QRCodeData data = gen.CreateQrCode(text, QRCodeGenerator.ECCLevel.M); PngByteQRCode png = new PngByteQRCode(data); byte[] bytes = png.GetGraphic(ppm, Color.Black, Color.White, true); File.WriteAllBytes(filePath, bytes); return filePath; } } /// /// Структура данных для конфигурации генерации QR-кода. /// Содержит параметры для создания полных ссылок с префиксом и суффиксом. /// [Serializable] public struct QRCodeInfo { /// /// Флаг, определяющий, нужно ли генерировать QR-код. /// public bool generateQRCode; /// /// Ранг QR-кода. /// public QRTier tier; /// /// Префикс ссылки (например, "https://example.com/"). /// public string linkPrefix; /// /// Шаблон сообщения для мессенджера. Используйте {0} для подстановки текста приза. /// [TextArea(2, 5)] [FormerlySerializedAs("suffix")] public string messageFormat; /// /// Короткий текст приза, который подставляется в шаблон сообщения. /// public string prizeText; /// /// Темный цвет в QR-коде. /// public Vector3 darkColor; /// /// Светлый цвет в QR-коде. /// public Vector3 lightColor; public static Color GetColor(Vector3 colorRGB) { Color outColor = Color.FromArgb(255, (int)(colorRGB.x * 255), (int)(colorRGB.y * 255), (int)(colorRGB.z * 255)); return outColor; } public static Vector3 GetTierDarkColorVector(QRTier tier) { return tier switch { QRTier.Bronze => new Vector3(166f / 255f, 104f / 255f, 64f / 255f), QRTier.Silver => new Vector3(112f / 255f, 112f / 255f, 112f / 255f), QRTier.Gold => new Vector3(184f / 255f, 134f / 255f, 11f / 255f), _ => new Vector3(0f, 0f, 0f) }; } public static Color GetTierDarkColor(QRTier tier) { return GetColor(GetTierDarkColorVector(tier)); } /// /// Формирует полную ссылку, объединяя префикс, данные и суффикс. /// /// Основные данные для включения в ссылку. /// Полная ссылка в формате: {linkPrefix}{data}?text={suffix} public string GetFullLink(string data) => $"{linkPrefix}{data}?text={ProcessSuffix(BuildMessageText())}"; public string BuildMessageText() { string format = messageFormat ?? string.Empty; string prize = prizeText ?? string.Empty; if (string.IsNullOrEmpty(format)) { return prize; } try { if (format.Contains("{0}")) { return string.Format(format, prize); } } catch (FormatException) { Debug.LogWarning($"[QRCodeInfo] Некорректный формат текста QR: '{format}'."); } if (string.IsNullOrWhiteSpace(prize)) { return format; } return $"{format}\n{prize}"; } private string ProcessSuffix(string rawSuffix) => Uri.EscapeDataString(rawSuffix); } }