killapp/Assets/Scripts/UI/Components/QRCodeGenerator.cs

269 lines
8.4 KiB
C#
Raw Permalink Normal View History

2026-05-18 08:42:33 +08:00
using UnityEngine;
using UnityEngine.UI;
using ZXing;
using ZXing.QrCode;
using ZXing.Common;
using ZXing.Rendering;
using ZXing.QrCode.Internal;
namespace Kill.UI.Components
{
/// <summary>
/// 二维码生成器
/// 支持生成用户ID等文本的二维码图片
/// </summary>
public class QRCodeGenerator : MonoBehaviour
{
[Header("显示组件")]
public RawImage qrCodeImage; // 显示二维码的RawImage
public int textureSize = 256; // 二维码图片尺寸(像素)
[Header("二维码样式")]
public Color foregroundColor = Color.black; // 前景色(二维码颜色)
public Color backgroundColor = Color.white; // 背景色
public int margin = 2; // 边距
// 当前生成的纹理
private Texture2D currentTexture;
// void Start()
// {
// Generate("123123");
// }
/// <summary>
/// 生成二维码
/// </summary>
/// <param name="content">二维码内容如用户ID</param>
public void Generate(string content)
{
if (string.IsNullOrEmpty(content))
{
Debug.LogWarning("[QRCodeGenerator] 内容为空,无法生成二维码");
return;
}
// 生成二维码纹理
Texture2D texture = GenerateQRCodeTexture(content, textureSize, textureSize);
if (texture != null)
{
// 清理旧纹理
if (currentTexture != null)
{
Destroy(currentTexture);
}
currentTexture = texture;
// 显示二维码
if (qrCodeImage != null)
{
qrCodeImage.texture = currentTexture;
qrCodeImage.SetNativeSize();
// 可以在这里调整显示大小
float scale = Mathf.Min(
qrCodeImage.rectTransform.rect.width / textureSize,
qrCodeImage.rectTransform.rect.height / textureSize
);
qrCodeImage.rectTransform.sizeDelta = new Vector2(textureSize * scale, textureSize * scale);
}
Debug.Log($"[QRCodeGenerator] 二维码生成成功: {content}");
}
}
/// <summary>
/// 生成用户ID二维码
/// </summary>
/// <param name="userId">用户ID</param>
public void GenerateUserQRCode(string userId)
{
// 可以添加前缀标识这是用户ID
string content = $"USER:{userId}";
Generate(content);
}
/// <summary>
/// 生成设备分享二维码
/// </summary>
/// <param name="deviceId">设备ID</param>
/// <param name="userId">用户ID</param>
public void GenerateDeviceShareQRCode(string deviceId, string userId)
{
// 格式: DEVICE:设备ID:用户ID
string content = $"DEVICE:{deviceId}:{userId}";
Generate(content);
}
/// <summary>
/// 生成二维码纹理
/// </summary>
private Texture2D GenerateQRCodeTexture(string content, int width, int height)
{
try
{
// 配置二维码参数
var options = new QrCodeEncodingOptions
{
Width = width,
Height = height,
Margin = margin,
CharacterSet = "UTF-8",
ErrorCorrection = ErrorCorrectionLevel.M // 中等容错率
};
// 创建写入器
var writer = new BarcodeWriter<Texture2D>
{
Format = BarcodeFormat.QR_CODE,
Options = options,
Renderer = new ZXingRender()
};
// 生成二维码
Texture2D texture = writer.Write(content);
// 应用颜色
ApplyColors(texture, foregroundColor, backgroundColor);
return texture;
}
catch (System.Exception ex)
{
Debug.LogError($"[QRCodeGenerator] 生成二维码失败: {ex.Message}");
return null;
}
}
/// <summary>
/// 应用自定义颜色到二维码
/// </summary>
private void ApplyColors(Texture2D texture, Color foreground, Color background)
{
Color32[] pixels = texture.GetPixels32();
for (int i = 0; i < pixels.Length; i++)
{
// 黑色像素变前景色,白色像素变背景色
if (pixels[i].r < 128)
{
pixels[i] = foreground;
}
else
{
pixels[i] = background;
}
}
texture.SetPixels32(pixels);
texture.Apply();
}
/// <summary>
/// 保存二维码到相册(移动端)
/// </summary>
public void SaveToGallery(string filename = "QRCode")
{
if (currentTexture == null)
{
Debug.LogWarning("[QRCodeGenerator] 没有可保存的二维码");
return;
}
// 将纹理转为PNG字节
byte[] bytes = currentTexture.EncodeToPNG();
// 保存到相册
#if UNITY_ANDROID
string path = $"/storage/emulated/0/DCIM/{filename}.png";
System.IO.File.WriteAllBytes(path, bytes);
// 刷新相册
using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
{
using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
{
using (AndroidJavaObject mediaScanner = new AndroidJavaObject("android.media.MediaScannerConnection"))
{
mediaScanner.CallStatic("scanFile", currentActivity, new string[] { path }, null, null);
}
}
}
#elif UNITY_IOS
// iOS 使用原生插件保存
// NativeGallery.SaveImageToGallery(currentTexture, "QRCode", filename);
#else
string path = System.IO.Path.Combine(Application.persistentDataPath, $"{filename}.png");
System.IO.File.WriteAllBytes(path, bytes);
Debug.Log($"[QRCodeGenerator] 二维码已保存到: {path}");
#endif
ToastUI.Show("二维码已保存到相册");
}
/// <summary>
/// 获取当前二维码纹理
/// </summary>
public Texture2D GetCurrentTexture()
{
return currentTexture;
}
/// <summary>
/// 清除二维码
/// </summary>
public void Clear()
{
if (currentTexture != null)
{
Destroy(currentTexture);
currentTexture = null;
}
if (qrCodeImage != null)
{
qrCodeImage.texture = null;
}
}
private void OnDestroy()
{
Clear();
}
}
/// <summary>
/// ZXing 纹理渲染器
/// </summary>
public class ZXingRender : IBarcodeRenderer<Texture2D>
{
public Texture2D Render(BitMatrix matrix, BarcodeFormat format, string content)
{
return Render(matrix, format, content, null);
}
public Texture2D Render(BitMatrix matrix, BarcodeFormat format, string content, EncodingOptions options)
{
int width = matrix.Width;
int height = matrix.Height;
Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
Color32[] pixels = new Color32[width * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
pixels[y * width + x] = matrix[x, y] ? Color.black : Color.white;
}
}
texture.SetPixels32(pixels);
texture.Apply();
texture.filterMode = FilterMode.Point; // 保持像素清晰
return texture;
}
}
}