269 lines
8.4 KiB
C#
269 lines
8.4 KiB
C#
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|