commit eeebb2070e5a0b976dafdbe097fa98fe039dfaee Author: xsl Date: Wed Mar 11 09:44:18 2026 +0800 init diff --git a/App.uvue b/App.uvue new file mode 100644 index 0000000..a3c0caf --- /dev/null +++ b/App.uvue @@ -0,0 +1,48 @@ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..a429bcb --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/main.uts b/main.uts new file mode 100644 index 0000000..07ed640 --- /dev/null +++ b/main.uts @@ -0,0 +1,9 @@ +import App from './App.uvue' + +import { createSSRApp } from 'vue' +export function createApp() { + const app = createSSRApp(App) + return { + app + } +} \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..690dbfd --- /dev/null +++ b/manifest.json @@ -0,0 +1,64 @@ +{ + "name": "test", + "appid": "__UNI__061EAF8", + "description": "", + "versionName": "1.0.0", + "versionCode": "100", + "uni-app-x": {}, + /* 快应用特有相关 */ + "quickapp": {}, + /* 小程序特有相关 */ + "mp-weixin": { + "appid": "", + "setting": { + "urlCheck": false + }, + "usingComponents": true + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3", + "app": { + "distribute": { + "icons": { + "android": { + "hdpi": "", + "xhdpi": "", + "xxhdpi": "", + "xxxhdpi": "" + } + } + } + }, + "app-android": { + "distribute": { + "modules": {}, + "icons": { + "hdpi": "", + "xhdpi": "", + "xxhdpi": "", + "xxxhdpi": "" + }, + "splashScreens": { + "default": {} + } + } + }, + "app-ios": { + "distribute": { + "modules": {}, + "icons": {}, + "splashScreens": {} + } + } +} \ No newline at end of file diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..10ab281 --- /dev/null +++ b/pages.json @@ -0,0 +1,27 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://doc.dcloud.net.cn/uni-app-x/collocation/pagesjson.html + { + "path": "pages/index/index", + "style": { + "navigationBarTitleText": "uni-app x" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "uni-app x", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "uniIdRouter": {}, + "condition" : { //模式配置,仅开发期间生效 + "current": 0, //当前激活的模式(list 的索引项) + "list": [ + { + "name": "", //模式名称 + "path": "", //启动页面,必选 + "query": "" //启动参数,在页面的onLoad函数里面得到 + } + ] + } +} diff --git a/pages/.DS_Store b/pages/.DS_Store new file mode 100644 index 0000000..bcd3a18 Binary files /dev/null and b/pages/.DS_Store differ diff --git a/pages/index/index.uvue b/pages/index/index.uvue new file mode 100644 index 0000000..f26fa57 --- /dev/null +++ b/pages/index/index.uvue @@ -0,0 +1,52 @@ + + + + + diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/static/logo.png differ diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..62eb87b --- /dev/null +++ b/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:12px; +$uni-font-size-base:14px; +$uni-font-size-lg:16px; + +/* 图片尺寸 */ +$uni-img-size-sm:20px; +$uni-img-size-base:26px; +$uni-img-size-lg:40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:20px; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:26px; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:15px; diff --git a/uni_modules/xtf-qrcode/.DS_Store b/uni_modules/xtf-qrcode/.DS_Store new file mode 100644 index 0000000..89a43a0 Binary files /dev/null and b/uni_modules/xtf-qrcode/.DS_Store differ diff --git a/uni_modules/xtf-qrcode/changelog.md b/uni_modules/xtf-qrcode/changelog.md new file mode 100644 index 0000000..b48cf76 --- /dev/null +++ b/uni_modules/xtf-qrcode/changelog.md @@ -0,0 +1,6 @@ +## 1.0.2(2025-03-04) +优化 +## 1.0.1(2025-02-10) +初始化 +## 1.0.0(2025-02-10) +初始化 diff --git a/uni_modules/xtf-qrcode/package.json b/uni_modules/xtf-qrcode/package.json new file mode 100644 index 0000000..e37b127 --- /dev/null +++ b/uni_modules/xtf-qrcode/package.json @@ -0,0 +1,91 @@ +{ + "id": "xtf-qrcode", + "displayName": "二维码生成 qrcode uts ", + "version": "1.0.2", + "description": "android/ios/web 通过平台sdk 生成二维码返回base64格式数据,可自行设置显示,动态二维码", + "keywords": [ + "二维码", + "生成二维码", + "动态二维码", + "二维码生成", + "qrcode" +], + "repository": "", + "engines": { + "HBuilderX": "^3.6.8" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "1.99" + }, + "sourcecode": { + "price": "10.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-android": "y", + "app-ios": "y", + "app-harmony": "n" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "n", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + }, + "dependencies": { + "qrcode": "^1.5.4", + "weapp-qrcode": "^1.0.0" + } +} diff --git a/uni_modules/xtf-qrcode/readme.md b/uni_modules/xtf-qrcode/readme.md new file mode 100644 index 0000000..edc5884 --- /dev/null +++ b/uni_modules/xtf-qrcode/readme.md @@ -0,0 +1,43 @@ +# xtf-qrcode +#### 若web 端报错,可用解压插件目录web.zip覆盖web文件夹文件 +### uniappx +``` + import {QrOpt,getQrData} from "@/uni_modules/xtf-qrcode" + + getQrData({ + content:"xtf", + logo:"/static/logo.png", + logoW:80, + logoH:80, + qrSize:300, + callback:function(data:string){ + // that.img=data; + //data 为base64图片 + } + } as QrOpt); + +``` +### uniapp +``` + import {getQrData} from "@/uni_modules/xtf-qrcode" + + getQrData({ + content:"xtf", + logo:"/static/logo.png", + logoW:80, + logoH:80, + qrSize:300, + callback:function(data:string){ + // that.img=data; + //data 为base64图片 + } + }); + +``` +二维码logo 宽高 建议为二维码大小的1/5 左右 +### 开发文档 +[UTS 语法](https://uniapp.dcloud.net.cn/tutorial/syntax-uts.html) +[UTS API插件](https://uniapp.dcloud.net.cn/plugin/uts-plugin.html) +[UTS uni-app兼容模式组件](https://uniapp.dcloud.net.cn/plugin/uts-component.html) +[UTS 标准模式组件](https://doc.dcloud.net.cn/uni-app-x/plugin/uts-vue-component.html) +[Hello UTS](https://gitcode.net/dcloud/hello-uts) \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/.DS_Store b/uni_modules/xtf-qrcode/utssdk/.DS_Store new file mode 100644 index 0000000..db151be Binary files /dev/null and b/uni_modules/xtf-qrcode/utssdk/.DS_Store differ diff --git a/uni_modules/xtf-qrcode/utssdk/app-android/QRCodeGenerator.java b/uni_modules/xtf-qrcode/utssdk/app-android/QRCodeGenerator.java new file mode 100644 index 0000000..edebd07 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-android/QRCodeGenerator.java @@ -0,0 +1,171 @@ + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.pdf.PdfRenderer; +import android.os.ParcelFileDescriptor; +import android.text.TextUtils; +import android.util.Log; +import android.util.Base64; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.ChecksumException; +import com.google.zxing.EncodeHintType; +import com.google.zxing.FormatException; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.NotFoundException; +import com.google.zxing.RGBLuminanceSource; +import com.google.zxing.Result; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.CharacterSetECI; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.pdf417.PDF417Writer; +import com.google.zxing.pdf417.encoder.Compaction; +import com.google.zxing.pdf417.encoder.Dimensions; +import com.google.zxing.pdf417.encoder.PDF417; +import com.google.zxing.qrcode.QRCodeReader; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +/** + * 二维码生成工具类 + */ +public class QRCodeGenerator { + private static final String TAG = "ZxingUtil"; + + + /** + * 在二维码中间添加Logo图案 + */ + private static Bitmap addLogo(Bitmap src,int logoW,int logoH, Bitmap logo) { + if (src == null) { + return null; + } + + if (logo == null) { + return src; + } + logo=resizeBitmap(logo,logoW,logoH); + // 获取图片的宽高 + int srcWidth = src.getWidth(); + int srcHeight = src.getHeight(); + int logoWidth = logo.getWidth(); + int logoHeight = logo.getHeight(); + + if (srcWidth == 0 || srcHeight == 0) { + return null; + } + + if (logoWidth == 0 || logoHeight == 0) { + return src; + } + + // logo大小为二维码整体大小的1/5 + // float scaleFactor = srcWidth * 1.0f / 5 / logoWidth; + Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, + Bitmap.Config.ARGB_8888); + try { + Canvas canvas = new Canvas(bitmap); + canvas.drawBitmap(src, 0, 0, null); + // canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2); + canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, + (srcHeight - logoHeight) / 2, null); + + canvas.save(); + canvas.restore(); + } catch (Exception e) { + bitmap = null; + e.getStackTrace(); + } + + return bitmap; + } + public static Bitmap generateQRCodeWithLogo(String content, int widthPix, + int heightPix,int logoW,int logoH, Bitmap logoBm) { + + if (content == null || "".equals(content)) { + return null; + } + Bitmap bitmap = null; + // 配置参数 + Map hints = new HashMap(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + // 容错级别 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + // 设置空白边距的宽度 + hints.put(EncodeHintType.MARGIN, 0); //default is 4 + + + // 图像数据转换,使用了矩阵转换 + BitMatrix bitMatrix; + try { + bitMatrix = new QRCodeWriter().encode(content, + BarcodeFormat.QR_CODE, widthPix, heightPix, hints); + + int[] pixels = new int[widthPix * heightPix]; + // 下面这里按照二维码的算法,逐个生成二维码的图片, + // 两个for循环是图片横列扫描的结果 + for (int y = 0; y < heightPix; y++) { + for (int x = 0; x < widthPix; x++) { + if (bitMatrix.get(x, y)) { + pixels[y * widthPix + x] = 0xff000000; + } else { + pixels[y * widthPix + x] = 0xffffffff; + } + } + } + + // 生成二维码图片的格式,使用ARGB_8888 + bitmap = Bitmap.createBitmap(widthPix, heightPix, + Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix); + + if (logoBm != null) { + bitmap = addLogo(bitmap, logoW,logoH,logoBm); + } + // if(!TextUtils.isEmpty(filePath)){ + + + // bitmap.compress(Bitmap.CompressFormat.JPEG, 100, + // new FileOutputStream(filePath));} + } catch (WriterException e) { + // + e.printStackTrace(); + } + return bitmap; + + } + + + public static Bitmap resizeBitmap(Bitmap originalBitmap, int newWidth, int newHeight) { + // 创建一个新的Bitmap对象,指定缩放后的宽度、高度和配置(这里使用与原Bitmap相同的配置) + Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true); + return resizedBitmap; + } + + + public static String convert(Bitmap bitmap) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + // 压缩Bitmap到字节数组中,格式为PNG,质量为100% + bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); + byte[] byteArray = byteArrayOutputStream.toByteArray(); + // 将字节数组编码为Base64字符串 + String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT); + return encoded; + } + +} diff --git a/uni_modules/xtf-qrcode/utssdk/app-android/Test.java b/uni_modules/xtf-qrcode/utssdk/app-android/Test.java new file mode 100644 index 0000000..22adeb7 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-android/Test.java @@ -0,0 +1,7 @@ +public class Test{ + public static String test(){ + return "xtf"; + } + + +} \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/app-android/config.json b/uni_modules/xtf-qrcode/utssdk/app-android/config.json new file mode 100644 index 0000000..9ba7638 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-android/config.json @@ -0,0 +1,7 @@ +{ + "minSdkVersion": "19", + "dependencies": [ + "com.google.zxing:core:3.4.1", + "com.journeyapps:zxing-android-embedded:4.3.0" + ] +} \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/app-android/index.uts b/uni_modules/xtf-qrcode/utssdk/app-android/index.uts new file mode 100644 index 0000000..5d9fbba --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-android/index.uts @@ -0,0 +1,45 @@ +import BitmapFactory from 'android.graphics.BitmapFactory'; + +export type QrOpt = { + content:string, + logo?:string, + qrSize?:number, + logoW?:number, + logoH?:number, + marign?:number, + callback:(data:string)=>void +} + +export function getQrData (opt:QrOpt):void{ + if(opt.qrSize==null){ + opt.qrSize=300; + } + console.log("--------------") + if(opt.logo==null){ + opt.callback("data:image/jpg;base64,"+QRCodeGenerator.convert(QRCodeGenerator.generateQRCodeWithLogo(opt.content,opt.qrSize!.toInt(),opt.qrSize!.toInt(),(0).toInt(),(0).toInt(),null))); + }else{ + try{ + var logo= UTSAndroid.getResourcePath(opt.logo!); + if(opt.logoW==null){ + opt.logoW=50; + } + if(opt.logoH==null){ + opt.logoW=50; + } + var bitmap= BitmapFactory.decodeFile(logo); + + opt.callback("data:image/jpg;base64,"+QRCodeGenerator.convert(QRCodeGenerator.generateQRCodeWithLogo(opt.content,opt.qrSize!.toInt(),opt.qrSize!.toInt(),opt.logoW!.toInt(),opt.logoH!.toInt(),bitmap))); + + }catch(e:Exception){ + opt.callback("data:image/jpg;base64,"+QRCodeGenerator.convert(QRCodeGenerator.generateQRCodeWithLogo(opt.content,opt.qrSize!.toInt(),opt.qrSize!.toInt(),(0).toInt(),(0).toInt(),null))); + } + + } + + + + + + +} + diff --git a/uni_modules/xtf-qrcode/utssdk/app-ios/config.json b/uni_modules/xtf-qrcode/utssdk/app-ios/config.json new file mode 100644 index 0000000..fa7d16c --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-ios/config.json @@ -0,0 +1,7 @@ +{ + "deploymentTarget": "12" + + // implementation 'com.google.zxing:core:3.4.1' + // implementation 'com.journeyapps:zxing-android-embedded:4.3.0' + +} diff --git a/uni_modules/xtf-qrcode/utssdk/app-ios/index.uts b/uni_modules/xtf-qrcode/utssdk/app-ios/index.uts new file mode 100644 index 0000000..a619574 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-ios/index.uts @@ -0,0 +1,40 @@ + +export type QrOpt = { + content:string, + logo?:string, + qrSize?:number, + logoW?:number, + logoH?:number, + marign?:number, + callback:(data:string)=>void + + +} + +export function getQrData (opt:QrOpt):void{ + console.log(opt.content) + if(opt.qrSize==null){ + opt.qrSize=300; + } + + if(opt.logo==null){ + var b=QR.createQrCode(opt.content,opt.qrSize!.toInt()); + console.log(b); + opt.callback("data:image/jpg;base64,"+b) + //return "data:image/jpg;base64,"+b; + }else{ + var l=UTSiOS.getResourcePath(opt.logo!) + if(opt.logoW==null){ + opt.logoW=50; + + } + if(opt.logoH==null){ + opt.logoH=50; + } + var b=QR.createQrCodeWithLogo(opt.content,opt.qrSize!.toInt(),l,opt.logoW!.toInt(),opt.logoH!.toInt()); + console.log(b); + opt.callback("data:image/jpg;base64,"+b) + + } + +} \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/app-ios/qr.swift b/uni_modules/xtf-qrcode/utssdk/app-ios/qr.swift new file mode 100644 index 0000000..b7ce805 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/app-ios/qr.swift @@ -0,0 +1,92 @@ +import CoreImage +import UIKit +import Foundation +import SwiftUICore + +public class QR{ + + + + static func imageToBase64(_ image: UIImage) -> String { + if let imageData = image.jpegData(compressionQuality: 1.0) { + // 使用imageData进行你的操作 + let base64String = imageData.base64EncodedString(options: []) + return base64String + + } + return ""; + } + + static func createQrCode(_ data:String,_ size:Int)->String{ + // 使用示例 + var b:CGFloat=CGFloat(size); + guard let qrCodeImage = QR.generateQRCode(with:data, qrSize: b) + else{ + return ""; + } + let q = QR.imageToBase64(qrCodeImage) + return q + } + + + static func createQrCodeWithLogo(_ data:String,_ size:Int,_ logo: String,_ logoW:Int,_ logoH:Int)->String{ + // 使用示例 + var b:CGFloat=CGFloat(size); + var w:CGFloat=CGFloat(logoW); + var h:CGFloat=CGFloat(logoH); + var logoSize:CGSize=CGSize(width: w, height: h) + guard let qrCodeImage = QR.generateQRCode(with:data,logoName:logo, logoSize:logoSize, qrSize: b) + else{ + return ""; + } + let q = QR.imageToBase64(qrCodeImage) + return q + } + // 生成二维码图像,并可选地添加logo + static func generateQRCode(with content: String, logoName: String? = nil, logoSize: CGSize = CGSize(width: 50, height: 50), qrSize: CGFloat = 200) -> UIImage? { + // 1. 生成二维码 + guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil } + let data = content.data(using: .utf8) + qrFilter.setValue(data, forKey: "inputMessage") + qrFilter.setValue("H", forKey: "inputCorrectionLevel") // 高纠错级别 + guard let qrImage = qrFilter.outputImage else { return nil } + + // 2. 调整二维码尺寸 + let scaleTransform = CGAffineTransform(scaleX: qrSize / qrImage.extent.size.width, y: qrSize / qrImage.extent.size.height) + let scaledQrImage = qrImage.transformed(by: scaleTransform) + + // 3. 创建UIImage对象 + guard let qrUIImage:UIImage? = UIImage(ciImage: scaledQrImage) else { return nil } + + + // if let image: UIImage? = someFunctionThatReturnsUIImage() { + // // 这里image已经被解包,并且是非空的 + // } else { + // // 处理image为nil的情况 + // } + // 4. 添加logo(如果有) + if let logoName = logoName, let logoImage = UIImage(named: logoName) { + let logoFrame = CGRect(x: (qrUIImage!.size.width - logoSize.width) / 2, + y: (qrUIImage!.size.height - logoSize.height) / 2, + width: logoSize.width, + height: logoSize.height) + + UIGraphicsBeginImageContextWithOptions(qrUIImage!.size, false, 0.0) + qrUIImage?.draw(in: CGRect(origin: .zero, size: qrUIImage!.size)) + logoImage.draw(in: logoFrame) + let finalImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return finalImage + } + + // 如果没有logo,直接返回二维码图像 + return qrUIImage + } + + + + + + +} \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/interface.uts b/uni_modules/xtf-qrcode/utssdk/interface.uts new file mode 100644 index 0000000..8f4ae87 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/interface.uts @@ -0,0 +1,47 @@ +/** + * interface.uts + * uts插件接口定义文件,按规范定义接口文件可以在HBuilderX中更好的做到语法提示 + */ + +/** + * myApi 异步函数的参数,在type里定义函数需要的参数以及api成功、失败的相关回调函数。 + */ +export type MyApiOptions = { + paramA : boolean + success ?: (res : MyApiResult) => void + fail ?: (res : MyApiFail) => void + complete ?: (res : any) => void +} + +/** + * 函数返回结果 + * 可以是void, 基本数据类型,自定义type, 或者其他类型。 + * [可选实现] + */ +export type MyApiResult = { + fieldA : number, + fieldB : boolean, + fieldC : string +} + +/** + * 错误码 + * 根据uni错误码规范要求,建议错误码以90开头,以下是错误码示例: + * - 9010001 错误信息1 + * - 9010002 错误信息2 + */ +export type MyApiErrorCode = 9010001 | 9010002; +/** + * myApi 的错误回调参数 + */ +export interface MyApiFail extends IUniError { + errCode : MyApiErrorCode +}; + +/* 异步函数定义 */ +export type MyApi = (options : MyApiOptions) => void + +/* 同步函数定义 */ +export type MyApiSync = (paramA : boolean) => MyApiResult + + diff --git a/uni_modules/xtf-qrcode/utssdk/unierror.uts b/uni_modules/xtf-qrcode/utssdk/unierror.uts new file mode 100644 index 0000000..c20aca6 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/unierror.uts @@ -0,0 +1,39 @@ +/* 此规范为 uni 规范,可以按照自己的需要选择是否实现 */ +import { MyApiErrorCode, MyApiFail } from "./interface.uts" +/** + * 错误主题 + * 注意:错误主题一般为插件名称,每个组件不同,需要使用时请更改。 + * [可选实现] + */ +export const UniErrorSubject = 'uts-api'; + + +/** + * 错误信息 + * @UniError + * [可选实现] + */ +export const MyAPIErrors : Map = new Map([ + /** + * 错误码及对应的错误信息 + */ + [9010001, 'custom error mseeage1'], + [9010002, 'custom error mseeage2'], +]); + + +/** + * 错误对象实现 + */ +export class MyApiFailImpl extends UniError implements MyApiFail { + + /** + * 错误对象构造函数 + */ + constructor(errCode : MyApiErrorCode) { + super(); + this.errSubject = UniErrorSubject; + this.errCode = errCode; + this.errMsg = MyAPIErrors.get(errCode) ?? ""; + } +} diff --git a/uni_modules/xtf-qrcode/utssdk/web.zip b/uni_modules/xtf-qrcode/utssdk/web.zip new file mode 100644 index 0000000..899c48b Binary files /dev/null and b/uni_modules/xtf-qrcode/utssdk/web.zip differ diff --git a/uni_modules/xtf-qrcode/utssdk/web/index.uts b/uni_modules/xtf-qrcode/utssdk/web/index.uts new file mode 100644 index 0000000..77059d4 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/web/index.uts @@ -0,0 +1,97 @@ + +import { QRCode } from './qrcode.min.js'; + +export type QrOpt = { + content:string, + logo?:string, + qrSize?:number, + logoW?:number, + logoH?:number, + marign?:number, + callback:(data:string)=>void +} + +export const getQrData = async function (opt:QrOpt){ + console.log(opt.content) + if(opt.qrSize==null){ + opt.qrSize=300; + } + + if(opt.marign==null){ + opt.marign=1; + } + // 要生成的二维码内容 + // var qrContent = "https://www.example.com"; + + //使用QRCode.toDataURL()方法生成base64字符串 + // QRCode.toDataURL(opt.content, { + // //errorCorrectionLevel: QRCode.CorrectLevel.H, // 容错级别 + // margin: 1, // 边距 + // width: opt.qrSize!, // 二维码宽度 + // height: opt.qrSize!, // 二维码高度 + // color: { + // dark: "#000000", // 前景色(二维码颜色) + // light: "#ffffff" // 背景色(空白区域颜色) + // } + // }).then(function(base64) { + // // 在这里,base64是包含二维码图片的base64字符串 + // // console.log(base64); + // opt.callback(base64); + // // return base64; + // // 你可以将base64字符串设置为img元素的src属性来显示二维码 + // // var img = document.createElement('img'); + // // img.src = base64; + // // document.body.appendChild(img); + + // // 你也可以将base64字符串用于其他目的,比如下载或传输 + // }).catch(function(error) { + // console.error("生成二维码时出错:", error); + // }); + + //return ""; + + + const qrcodeCanvas = document.createElement('canvas'); + qrcodeCanvas.width = opt.qrSize!; + qrcodeCanvas.height = opt.qrSize!; + + // 使用QRCode对象生成二维码 + await QRCode.toCanvas(qrcodeCanvas, opt.content, { width: opt.qrSize!,height: opt.qrSize!,margin: opt.marign!}, (error) => { + if (error) console.error(error); + }); + if(opt.logo==null){ + opt.callback(qrcodeCanvas.toDataURL('image/png')) + return; + } + + // 获取logo图片 + const logoImage = new Image(); + logoImage.src = opt.logo!; // 替换为你的logo图片路径 + logoImage.onload = () => { + // 创建一个用于合成带有logo的二维码的canvas元素 + const logoQRCodeCanvas = document.createElement('canvas'); + logoQRCodeCanvas.width = qrcodeCanvas.width; + logoQRCodeCanvas.height = qrcodeCanvas.height; + const ctx = logoQRCodeCanvas.getContext('2d'); + + // 将基本的二维码绘制到新的canvas上 + ctx.drawImage(qrcodeCanvas, 0, 0); + + // 计算logo的大小和位置 + const logoSize = opt.logoW!; // logo的显示大小 + const logoX = (logoQRCodeCanvas.width - opt.logoW!) / 2; + const logoY = (logoQRCodeCanvas.height - opt.logoH!) / 2; + + // 在二维码上绘制logo + ctx.drawImage(logoImage, logoX, logoY, logoSize, opt.logoH); + + // 将带有logo的二维码canvas转换为base64图片 + const base64Image = logoQRCodeCanvas.toDataURL('image/png'); + + // 将base64图片存储到组件的数据中 + // this.qrcodeWithLogo = base64Image; + opt.callback(base64Image) + }; + + +} \ No newline at end of file diff --git a/uni_modules/xtf-qrcode/utssdk/web/qrcode.min.js b/uni_modules/xtf-qrcode/utssdk/web/qrcode.min.js new file mode 100644 index 0000000..b147837 --- /dev/null +++ b/uni_modules/xtf-qrcode/utssdk/web/qrcode.min.js @@ -0,0 +1,11 @@ +/** + * Skipped minification because the original files appears to be already minified. + * Original file: /npm/qrcode@1.5.1/build/qrcode.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +export var QRCode=function(t){"use strict";var r,e=function(){return"function"==typeof Promise&&Promise.prototype&&Promise.prototype.then},n=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706],o=function(t){if(!t)throw new Error('"version" cannot be null or undefined');if(t<1||t>40)throw new Error('"version" should be in range from 1 to 40');return 4*t+17},a=function(t){return n[t]},i=function(t){for(var r=0;0!==t;)r++,t>>>=1;return r},u=function(t){if("function"!=typeof t)throw new Error('"toSJISFunc" is not a valid function.');r=t},s=function(){return void 0!==r},f=function(t){return r(t)};function h(t,r){return t(r={exports:{}},r.exports),r.exports}var c=h((function(t,r){r.L={bit:1},r.M={bit:0},r.Q={bit:3},r.H={bit:2},r.isValid=function(t){return t&&void 0!==t.bit&&t.bit>=0&&t.bit<4},r.from=function(t,e){if(r.isValid(t))return t;try{return function(t){if("string"!=typeof t)throw new Error("Param is not a string");switch(t.toLowerCase()){case"l":case"low":return r.L;case"m":case"medium":return r.M;case"q":case"quartile":return r.Q;case"h":case"high":return r.H;default:throw new Error("Unknown EC Level: "+t)}}(t)}catch(t){return e}}}));function g(){this.buffer=[],this.length=0}c.L,c.M,c.Q,c.H,c.isValid,g.prototype={get:function(t){var r=Math.floor(t/8);return 1==(this.buffer[r]>>>7-t%8&1)},put:function(t,r){for(var e=0;e>>r-e-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var r=Math.floor(this.length/8);this.buffer.length<=r&&this.buffer.push(0),t&&(this.buffer[r]|=128>>>this.length%8),this.length++}};var d=g;function l(t){if(!t||t<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=t,this.data=new Uint8Array(t*t),this.reservedBit=new Uint8Array(t*t)}l.prototype.set=function(t,r,e,n){var o=t*this.size+r;this.data[o]=e,n&&(this.reservedBit[o]=!0)},l.prototype.get=function(t,r){return this.data[t*this.size+r]},l.prototype.xor=function(t,r,e){this.data[t*this.size+r]^=e},l.prototype.isReserved=function(t,r){return this.reservedBit[t*this.size+r]};var v=l,p=h((function(t,r){var e=o;r.getRowColCoords=function(t){if(1===t)return[];for(var r=Math.floor(t/7)+2,n=e(t),o=145===n?26:2*Math.ceil((n-13)/(2*r-2)),a=[n-7],i=1;i=0&&t<=7},r.from=function(t){return r.isValid(t)?parseInt(t,10):void 0},r.getPenaltyN1=function(t){for(var r=t.size,n=0,o=0,a=0,i=null,u=null,s=0;s=5&&(n+=e+(o-5)),i=h,o=1),(h=t.get(f,s))===u?a++:(a>=5&&(n+=e+(a-5)),u=h,a=1)}o>=5&&(n+=e+(o-5)),a>=5&&(n+=e+(a-5))}return n},r.getPenaltyN2=function(t){for(var r=t.size,e=0,o=0;o=10&&(1488===n||93===n)&&e++,a=a<<1&2047|t.get(u,i),u>=10&&(1488===a||93===a)&&e++}return e*o},r.getPenaltyN4=function(t){for(var r=0,e=t.data.length,n=0;n=0;){for(var n=e[0],o=0;o0){var o=new Uint8Array(this.degree);return o.set(e,n),o}return e};var L=T,b=function(t){return!isNaN(t)&&t>=1&&t<=40},U="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+",x="(?:(?![A-Z0-9 $%*+\\-./:]|"+(U=U.replace(/u/g,"\\u"))+")(?:.|[\r\n]))+",k=new RegExp(U,"g"),F=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g"),S=new RegExp(x,"g"),D=new RegExp("[0-9]+","g"),Y=new RegExp("[A-Z $%*+\\-./:]+","g"),_=new RegExp("^"+U+"$"),z=new RegExp("^[0-9]+$"),H=new RegExp("^[A-Z0-9 $%*+\\-./:]+$"),J={KANJI:k,BYTE_KANJI:F,BYTE:S,NUMERIC:D,ALPHANUMERIC:Y,testKanji:function(t){return _.test(t)},testNumeric:function(t){return z.test(t)},testAlphanumeric:function(t){return H.test(t)}},K=h((function(t,r){r.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]},r.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]},r.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]},r.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]},r.MIXED={bit:-1},r.getCharCountIndicator=function(t,r){if(!t.ccBits)throw new Error("Invalid mode: "+t);if(!b(r))throw new Error("Invalid version: "+r);return r>=1&&r<10?t.ccBits[0]:r<27?t.ccBits[1]:t.ccBits[2]},r.getBestModeForData=function(t){return J.testNumeric(t)?r.NUMERIC:J.testAlphanumeric(t)?r.ALPHANUMERIC:J.testKanji(t)?r.KANJI:r.BYTE},r.toString=function(t){if(t&&t.id)return t.id;throw new Error("Invalid mode")},r.isValid=function(t){return t&&t.bit&&t.ccBits},r.from=function(t,e){if(r.isValid(t))return t;try{return function(t){if("string"!=typeof t)throw new Error("Param is not a string");switch(t.toLowerCase()){case"numeric":return r.NUMERIC;case"alphanumeric":return r.ALPHANUMERIC;case"kanji":return r.KANJI;case"byte":return r.BYTE;default:throw new Error("Unknown mode: "+t)}}(t)}catch(t){return e}}}));K.NUMERIC,K.ALPHANUMERIC,K.BYTE,K.KANJI,K.MIXED,K.getCharCountIndicator,K.getBestModeForData,K.isValid;var O=h((function(t,r){var e=i(7973);function n(t,r){return K.getCharCountIndicator(t,r)+4}function o(t,r){var e=0;return t.forEach((function(t){var o=n(t.mode,r);e+=o+t.getBitsLength()})),e}r.from=function(t,r){return b(t)?parseInt(t,10):r},r.getCapacity=function(t,r,e){if(!b(t))throw new Error("Invalid QR Code version");void 0===e&&(e=K.BYTE);var o=8*(a(t)-M(t,r));if(e===K.MIXED)return o;var i=o-n(e,t);switch(e){case K.NUMERIC:return Math.floor(i/10*3);case K.ALPHANUMERIC:return Math.floor(i/11*2);case K.KANJI:return Math.floor(i/13);case K.BYTE:default:return Math.floor(i/8)}},r.getBestVersionForData=function(t,e){var n,a=c.from(e,c.M);if(Array.isArray(t)){if(t.length>1)return function(t,e){for(var n=1;n<=40;n++){if(o(t,n)<=r.getCapacity(n,e,K.MIXED))return n}}(t,a);if(0===t.length)return 1;n=t[0]}else n=t;return function(t,e,n){for(var o=1;o<=40;o++)if(e<=r.getCapacity(o,n,t))return o}(n.mode,n.getLength(),a)},r.getEncodedBits=function(t){if(!b(t)||t<7)throw new Error("Invalid QR Code version");for(var r=t<<12;i(r)-e>=0;)r^=7973<=0;)n^=1335<0&&(e=this.data.substr(r),n=parseInt(e,10),t.put(n,3*o+1))};var j=q,$=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function X(t){this.mode=K.ALPHANUMERIC,this.data=t}X.getBitsLength=function(t){return 11*Math.floor(t/2)+t%2*6},X.prototype.getLength=function(){return this.data.length},X.prototype.getBitsLength=function(){return X.getBitsLength(this.data.length)},X.prototype.write=function(t){var r;for(r=0;r+2<=this.data.length;r+=2){var e=45*$.indexOf(this.data[r]);e+=$.indexOf(this.data[r+1]),t.put(e,11)}this.data.length%2&&t.put($.indexOf(this.data[r]),6)};var Z=X;function W(t){this.mode=K.BYTE,"string"==typeof t&&(t=function(t){for(var r=[],e=t.length,n=0;n=55296&&o<=56319&&e>n+1){var a=t.charCodeAt(n+1);a>=56320&&a<=57343&&(o=1024*(o-55296)+a-56320+65536,n+=1)}o<128?r.push(o):o<2048?(r.push(o>>6|192),r.push(63&o|128)):o<55296||o>=57344&&o<65536?(r.push(o>>12|224),r.push(o>>6&63|128),r.push(63&o|128)):o>=65536&&o<=1114111?(r.push(o>>18|240),r.push(o>>12&63|128),r.push(o>>6&63|128),r.push(63&o|128)):r.push(239,191,189)}return new Uint8Array(r).buffer}(t)),this.data=new Uint8Array(t)}W.getBitsLength=function(t){return 8*t},W.prototype.getLength=function(){return this.data.length},W.prototype.getBitsLength=function(){return W.getBitsLength(this.data.length)},W.prototype.write=function(t){for(var r=0,e=this.data.length;r=33088&&e<=40956)e-=33088;else{if(!(e>=57408&&e<=60351))throw new Error("Invalid SJIS character: "+this.data[r]+"\nMake sure your charset is UTF-8");e-=49472}e=192*(e>>>8&255)+(255&e),t.put(e,13)}};var rt=tt,et=h((function(t){var r={single_source_shortest_paths:function(t,e,n){var o={},a={};a[e]=0;var i,u,s,f,h,c,g,d=r.PriorityQueue.make();for(d.push(e,0);!d.empty();)for(s in u=(i=d.pop()).value,f=i.cost,h=t[u]||{})h.hasOwnProperty(s)&&(c=f+h[s],g=a[s],(void 0===a[s]||g>c)&&(a[s]=c,d.push(s,c),o[s]=u));if(void 0!==n&&void 0===a[n]){var l=["Could not find a path from ",e," to ",n,"."].join("");throw new Error(l)}return o},extract_shortest_path_from_predecessor_list:function(t,r){for(var e=[],n=r;n;)e.push(n),n=t[n];return e.reverse(),e},find_path:function(t,e,n){var o=r.single_source_shortest_paths(t,e,n);return r.extract_shortest_path_from_predecessor_list(o,n)},PriorityQueue:{make:function(t){var e,n=r.PriorityQueue,o={};for(e in t=t||{},n)n.hasOwnProperty(e)&&(o[e]=n[e]);return o.queue=[],o.sorter=t.sorter||n.default_sorter,o},default_sorter:function(t,r){return t.cost-r.cost},push:function(t,r){var e={value:t,cost:r};this.queue.push(e),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return 0===this.queue.length}}};t.exports=r})),nt=h((function(t,r){function e(t){return unescape(encodeURIComponent(t)).length}function n(t,r,e){for(var n,o=[];null!==(n=t.exec(e));)o.push({data:n[0],index:n.index,mode:r,length:n[0].length});return o}function o(t){var r,e,o=n(J.NUMERIC,K.NUMERIC,t),a=n(J.ALPHANUMERIC,K.ALPHANUMERIC,t);return s()?(r=n(J.BYTE,K.BYTE,t),e=n(J.KANJI,K.KANJI,t)):(r=n(J.BYTE_KANJI,K.BYTE,t),e=[]),o.concat(a,r,e).sort((function(t,r){return t.index-r.index})).map((function(t){return{data:t.data,mode:t.mode,length:t.length}}))}function a(t,r){switch(r){case K.NUMERIC:return j.getBitsLength(t);case K.ALPHANUMERIC:return Z.getBitsLength(t);case K.KANJI:return rt.getBitsLength(t);case K.BYTE:return G.getBitsLength(t)}}function i(t,r){var e,n=K.getBestModeForData(t);if((e=K.from(r,n))!==K.BYTE&&e.bit=0?t[t.length-1]:null;return e&&e.mode===r.mode?(t[t.length-1].data+=r.data,t):(t.push(r),t)}),[])}(s))},r.rawSplit=function(t){return r.fromArray(o(t))}}));function ot(t,r,e){var n,o,a=t.size,i=V(r,e);for(n=0;n<15;n++)o=1==(i>>n&1),n<6?t.set(n,8,o,!0):n<8?t.set(n+1,8,o,!0):t.set(a-15+n,8,o,!0),n<8?t.set(8,a-n-1,o,!0):n<9?t.set(8,15-n-1+1,o,!0):t.set(8,15-n-1,o,!0);t.set(a-8,8,1,!0)}function at(t,r,e){var n=new d;e.forEach((function(r){n.put(r.mode.bit,4),n.put(r.getLength(),K.getCharCountIndicator(r.mode,t)),r.write(n)}));var o=8*(a(t)-M(t,r));for(n.getLengthInBits()+4<=o&&n.put(0,4);n.getLengthInBits()%8!=0;)n.putBit(0);for(var i=(o-n.getLengthInBits())/8,u=0;u=0&&u<=6&&(0===s||6===s)||s>=0&&s<=6&&(0===u||6===u)||u>=2&&u<=4&&s>=2&&s<=4?t.set(a+u,i+s,!0,!0):t.set(a+u,i+s,!1,!0))}(c,r),function(t){for(var r=t.size,e=8;e=7&&function(t,r){for(var e,n,o,a=t.size,i=O.getEncodedBits(r),u=0;u<18;u++)e=Math.floor(u/3),n=u%3+a-8-3,o=1==(i>>u&1),t.set(e,n,o,!0),t.set(n,e,o,!0)}(c,r),function(t,r){for(var e=t.size,n=-1,o=e-1,a=7,i=0,u=e-1;u>0;u-=2)for(6===u&&u--;;){for(var s=0;s<2;s++)if(!t.isReserved(o,u-s)){var f=!1;i>>a&1)),t.set(o,u-s,f),-1===--a&&(i++,a=7)}if((o+=n)<0||e<=o){o-=n,n=-n;break}}}(c,f),isNaN(n)&&(n=E.getBestMask(c,ot.bind(null,c,e))),E.applyMask(n,c),ot(c,e,n),{modules:c,version:r,errorCorrectionLevel:e,maskPattern:n,segments:a}}nt.fromArray,nt.fromString,nt.rawSplit;var ut=function(t,r){if(void 0===t||""===t)throw new Error("No input text");var e,n,o=c.M;return void 0!==r&&(o=c.from(r.errorCorrectionLevel,c.M),e=O.from(r.version),n=E.from(r.maskPattern),r.toSJISFunc&&u(r.toSJISFunc)),it(t,e,o,n)},st=h((function(t,r){function e(t){if("number"==typeof t&&(t=t.toString()),"string"!=typeof t)throw new Error("Color should be defined as hex string");var r=t.slice().replace("#","").split("");if(r.length<3||5===r.length||r.length>8)throw new Error("Invalid hex color: "+t);3!==r.length&&4!==r.length||(r=Array.prototype.concat.apply([],r.map((function(t){return[t,t]})))),6===r.length&&r.push("F","F");var e=parseInt(r.join(""),16);return{r:e>>24&255,g:e>>16&255,b:e>>8&255,a:255&e,hex:"#"+r.slice(0,6).join("")}}r.getOptions=function(t){t||(t={}),t.color||(t.color={});var r=void 0===t.margin||null===t.margin||t.margin<0?4:t.margin,n=t.width&&t.width>=21?t.width:void 0,o=t.scale||4;return{width:n,scale:n?4:o,margin:r,color:{dark:e(t.color.dark||"#000000ff"),light:e(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}},r.getScale=function(t,r){return r.width&&r.width>=t+2*r.margin?r.width/(t+2*r.margin):r.scale},r.getImageWidth=function(t,e){var n=r.getScale(t,e);return Math.floor((t+2*e.margin)*n)},r.qrToImageData=function(t,e,n){for(var o=e.modules.size,a=e.modules.data,i=r.getScale(o,n),u=Math.floor((o+2*n.margin)*i),s=n.margin*i,f=[n.color.light,n.color.dark],h=0;h=s&&c>=s&&h':"",s="0&&s>0&&t[u-1]||(n+=a?ct("M",s+e,.5+f+e):ct("m",o,0),o=0,a=!1),s+1',f='viewBox="0 0 '+i+" "+i+'"',h=''+u+s+"\n";return"function"==typeof e&&e(null,h),h};function dt(t,r,n,o,a){var i=[].slice.call(arguments,1),u=i.length,s="function"==typeof i[u-1];if(!s&&!e())throw new Error("Callback required as last argument");if(!s){if(u<1)throw new Error("Too few arguments provided");return 1===u?(n=r,r=o=void 0):2!==u||r.getContext||(o=n,n=r,r=void 0),new Promise((function(e,a){try{var i=ut(n,o);e(t(i,r,o))}catch(t){a(t)}}))}if(u<2)throw new Error("Too few arguments provided");2===u?(a=n,n=r,r=o=void 0):3===u&&(r.getContext&&void 0===a?(a=o,o=void 0):(a=o,o=n,n=r,r=void 0));try{var f=ut(n,o);a(null,t(f,r,o))}catch(t){a(t)}}var lt=ut,vt=dt.bind(null,ft.render),pt=dt.bind(null,ft.renderToDataURL),wt=dt.bind(null,(function(t,r,e){return gt(t,e)})),mt={create:lt,toCanvas:vt,toDataURL:pt,toString:wt};return t.create=lt,t.default=mt,t.toCanvas=vt,t.toDataURL=pt,t.toString=wt,Object.defineProperty(t,"__esModule",{value:!0}),t}({}); + + + + \ No newline at end of file diff --git a/uni_modules/xwq-mlkit-scan-code/changelog.md b/uni_modules/xwq-mlkit-scan-code/changelog.md new file mode 100644 index 0000000..009ec0c --- /dev/null +++ b/uni_modules/xwq-mlkit-scan-code/changelog.md @@ -0,0 +1,252 @@ +## 1.15.0(2026-03-08) +补充文档说明 +## 1.14.9(2026-01-27) +* 识别结果回调参数增加识别码类型字段scanCodeType返回 +## 1.14.8(2026-01-21) +* 更新安卓端部分依赖版本到1.4,解决上架Google商店要求16k导致上架失败的问题 +## 1.14.7(2026-01-13) +* 优化IOS端关闭扫码页逻辑 +## 1.14.6(2026-01-12) +* iOS端识别不到二维码Toast弹窗支持根据内容自适应 +## 1.14.5(2026-01-12) +* 相册图片识别-增加自定义未识别到二维码提示内容 +## 1.14.4(2026-01-04) +* IOS端支持配置直接返回数据(包括多个码结果) +## 1.14.3(2025-12-31) +* 安卓端支持配置直接返回数据(包括多个码结果) +## 1.14.2(2025-12-30) +* IOS端调整对焦模式为优先自动对焦 +* 已知问题优化 +## 1.14.1(2025-12-22) +* 修复uniapp项目云打包报错的问题 +## 1.14.0(2025-12-21) +### 重要更新 +* 将参数中的扫码格式设置类型由number调整为string,为了更灵活的配置多种格式扫码 +* 连续扫码场景支持间隔时间动态控制,参照用例 +* 连续扫码场景增加暂停扫码控制,适配更多的业务场景 +* 安卓端修复在连续扫码中可能出现回调两次的问题 +## 1.13.1(2025-12-19) +* 消除控制台报解析器已关闭的错误 +* 补充文档说明 +## 1.13.0(2025-12-18) +* 苹果端针对iPhone15及以上机型,需要近距离扫码特定场景增加参数配置 +## 1.12.9(2025-12-17) +* 修复IOS端偶发性回调两次的问题 +* IOS端增加对页面多次调用的拦截操作 +## 1.12.8(2025-12-17) +* 修复安卓端相册识别后数据类型转换错误的问题 +## 1.12.7(2025-12-17) +* IOS端补充product类型条码的返回字段,与安卓保持一致 +## 1.12.6(2025-12-17) +* 修复部分条码返回值不准确的问题 +## 1.12.5(2025-12-15) +* 移除安卓端的调试信息 +## 1.12.4(2025-12-15) +* 安卓端修复计算值丢失精度的问题 +## 1.12.3(2025-12-15) +* 适配小米澎湃系统识别多码时预览图不全屏问题 +## 1.12.2(2025-12-15) +* 针对安卓小米机型调试 +## 1.12.1(2025-12-15) +* 适配安卓小米澎湃系统某些机型识别到多个二维码,预览图没有覆盖屏幕的问题 +## 1.12.0(2025-12-15) +* 针对安卓小米澎湃系统调试 +## 1.11.9(2025-12-15) +* 增加调试信息 +## 1.11.8(2025-12-15) +* 安卓端针对小米机型调试 +## 1.11.7(2025-12-14) +* 增加调试log +## 1.11.6(2025-12-14) +* 安卓端优化识别到多个二维码结果,预览图没有铺满屏幕的情况 +* 增加识别到多个二维码结果,底部提示文案的内容、颜色、字号大小自定义配置 +## 1.11.5(2025-12-10) +* 针对iPhone15优化测试 +## 1.11.4(2025-12-09) +* 安卓端优化中间区域扫码模式,四拐角样式绘制适配屏幕大小 +## 1.11.3(2025-12-09) +* 修复IOS端云打包错误的问题 +## 1.11.2(2025-12-09) +* IOS端增加log打印测试 +## 1.11.1(2025-12-08) +* IOS端增加超广角对焦模式触发主动对焦处理 +* 安卓端优化多码识别结果标记处理 +## 1.11.0(2025-12-06) +* 修改安卓端扫码模式默认为全屏模式 +## 1.10.9(2025-12-04) +* IOS端优化,解决某些机型识别成功后扫码页面未完全关闭的问题 +## 1.10.8(2025-12-04) +* 修复安卓端聚焦模糊的问题 +* 优化安卓端条码的识别效率 +## 1.10.7(2025-11-26) +* 安卓端sdk支持最低版本改为默认为21 +## 1.10.6(2025-11-26) +* 安卓端增加多点自动对焦,提升识别效率 +## 1.10.5(2025-11-24) +* 优化安卓端单码识别速度 +* IOS端新增侧滑关闭扫码页功能 +## 1.10.4(2025-11-23) +* 优化IOS端多码识别 +## 1.10.3(2025-11-21) +* 补充鸿蒙端字段声明 +## 1.10.2(2025-11-18) +* 优化iOS端近距离扫码 +## 1.10.1(2025-11-18) +* IOS端增加log信息打印 +## 1.10.0(2025-11-17) +* 修复安卓端相册二维码识别问题 +## 1.9.9(2025-11-15) +* 优化IOS端多码识别 +## 1.9.8(2025-11-15) +* 优化IOS端近距离无法识别条码的问题 +* IOS端新增scanbox高度自定义配置 +## 1.9.7(2025-11-13) +* 安卓端支持设置scanbox模式扫码框的高度自定义配置 +## 1.9.6(2025-11-12) +* 完善IOS端scanbox模式扫码逻辑 +## 1.9.5(2025-11-11) +* 补充IOS端scanbox扫码模式UI +## 1.9.4(2025-11-11) +* 优化入参处理逻辑 +* 补充中间扫码模式文档说明 +## 1.9.3(2025-11-08) +* IOS端支持扫码格式设置 +* IOS端细节优化 +## 1.9.2(2025-11-08) +* 细节优化 +## 1.9.1(2025-10-26) +* 兼容鸿蒙端扫码 +* 注意:鸿蒙使用的是官方默认扫码界面,不能自定义界面内容,只能单码识别,不支持连续扫码 +## 1.9.0(2025-10-25) +* 增加连续扫码场景,toast提示内容自定义配置 +## 1.8.9(2025-10-24) +*升级安卓谷歌扫码依赖到17.3.0版本 +*最低支持版本提到26 +## 1.8.8(2025-09-24) +IOS端补充主动关闭扫码页面的方法 +## 1.8.7(2025-09-23) +修复uniapp项目打包失败的问题 +## 1.8.6(2025-09-22) +优化主动关闭扫码页方法判断,兼容uniapp端V2项目 +## 1.8.5(2025-09-19) +安卓端增加主动关闭扫码页的方法 +## 1.8.4(2025-09-19) +移除无用代码 +## 1.8.3(2025-09-18) +调整web目录文件后缀 +## 1.8.2(2025-09-18) +新增web平台目录 +## 1.8.1(2025-08-06) +更新安卓端依赖到最新版本 +## 1.8.0(2025-05-24) +安卓端 +fix: 修复由1.7.9版本引起的识别多个二维码后,左上角叉不能关闭的bug + +Feat-重要更新: 1. 安卓新增跟随IOS界面样式配置选项 + + 2. 新增二维码识别中自动缩放相机功能配置 +## 1.7.9(2025-05-22) +修复安卓端灯光切换的需要点两次的bug +## 1.7.8(2025-05-22) +重要:安卓端支持手动聚焦缩放功能 +## 1.7.7(2025-05-21) +调整灯光文案自定义字段,由原来的一个变为两个,可参考用例 +## 1.7.6(2025-05-21) +适配新的二维码制式 +## 1.7.5(2025-05-13) +移除无用代码 +## 1.7.4(2025-05-10) +feat(重要):IOS端增加手动对焦、自动曝光功能 +## 1.7.3(2025-04-29) +调整文案宽度自适应 +## 1.7.2(2025-04-28) +适配文案动态修改 +## 1.7.1(2025-04-28) +增加相册、手电筒文案自定义 +## 1.7.0(2025-04-23) +1.IOS端增加灯光功能 +2.适配灯光功能动态配置 +## 1.6.5(2025-04-22) +修复关闭扫码页,顶部出现扫描线条的bug +## 1.6.4(2025-04-22) +1.IOS端增加相册入口动态配置 +2.IOS端在连续扫码情况下,增加toast提示配置 +## 1.6.3(2025-04-21) +1.修复IOS无法关闭页面的bug +2.IOS端增加底部文案动态配置 +## 1.6.2(2025-04-21) +修复IOS关闭扫码页失败的问题 +## 1.6.1(2025-04-21) +平板设备增加打印信息 +## 1.6.0(2025-04-21) +安卓 端增加测试log打印 +## 1.5.9(2025-04-21) +IOS端增加识别成功音效 +## 1.5.8(2025-04-20) +重要:IOS端增加多码识别 +## 1.5.7(2025-04-13) +1、增加用户取消扫码回调方法 +2、移除平台目录下的类型声明,统一使用interface文件,升级后需注意调整代码 +## 1.5.6(2025-04-10) +IOS端修复草料二维码识别失败的问题 +## 1.5.5(2025-03-22) +iOS端启动扫码预览逻辑优化 +## 1.5.4(2025-03-15) +ios更新:增加相册二维码识别 +## 1.5.3(2025-03-14) +开启源码授权 +## 1.5.2(2025-02-27) +ios端增加连续扫码 +## 1.5.1(2025-02-25) +修复iOS扫码窗口关闭,返回按钮未移除的问题 +## 1.5.0(2025-02-24) +增加iOS端的支持 +## 1.4.0(2025-02-19) +增加连续扫码识别成功toast提示 +## 1.3.9(2025-02-11) +修复识别多个二维码成功后,摄像头预览未正常关闭的问题 +## 1.3.8(2025-01-14) +适配邮件二维码识别 +## 1.3.7(2025-01-10) +增加ISBN二维码识别 +## 1.3.6(2024-12-30) +开启摄像头信息打印 +## 1.3.5(2024-12-18) +细节优化 +## 1.3.4(2024-12-17) +增加相册、灯光显示动态控制 +## 1.3.3(2024-12-17) +针对不同机型优化摄像头打开模式 +## 1.3.2(2024-12-16) +增加前后摄像头切换功能 +## 1.3.1(2024-12-16) +解决开启连续扫码,回调函数只触发一次的问题 +## 1.3(2024-12-14) +增加连续扫码参数配置 +## 1.2.5(2024-10-28) +移除无用代码 +## 1.2.4(2024-10-28) +修复由工具4.31版本引起的颜色设置失效问题,注意:调整了多色的传值类型,可参照下列文档说明 +## 1.2.3(2024-10-27) +修复工具4.31引起的OptionType未引入的错误 +## 1.2.2(2024-10-25) +移除调试代码 +## 1.2.1(2024-10-25) +优化图像解析分辨率逻辑 +## 1.2.0(2024-10-19) +1.优化识别到二维码标记的UI样式 +2.增加超时未识别到二维码回调error函数 +3.二维码解析细节优化 +## 1.1.1(2024-10-07) +增加物料二维码内容正常读取返回 +## 1.1.0(2024-09-29) +适配uniapp项目扫码 +## 1.0.3(2024-08-13) +更新使用文档 +## 1.0.2(2024-08-13) +优化 +## 1.0.1(2024-04-18) +1.增加返回参数类型 +2.修改返回值的格式 +## 1.0.0(2024-04-10) +初始化 diff --git a/uni_modules/xwq-mlkit-scan-code/encrypt b/uni_modules/xwq-mlkit-scan-code/encrypt new file mode 100644 index 0000000..f1f6e24 --- /dev/null +++ b/uni_modules/xwq-mlkit-scan-code/encrypt @@ -0,0 +1 @@ +^ <̥H1D@E^*s٠N"T>in%%nz*Je(JK[c%[xBZqϧo[Ko>; ? ykWe؁|S Ԁζ #.R_/6hLQ}(-E \ No newline at end of file diff --git a/uni_modules/xwq-mlkit-scan-code/package.json b/uni_modules/xwq-mlkit-scan-code/package.json new file mode 100644 index 0000000..0a2926f --- /dev/null +++ b/uni_modules/xwq-mlkit-scan-code/package.json @@ -0,0 +1,120 @@ +{ + "id": "xwq-mlkit-scan-code", + "displayName": "(兼容IOS、安卓、鸿蒙)二维码、条码识别,mlkit扫码插件(毫秒级识别效率,支持多码识别,连续扫码)", + "version": "1.15.0", + "description": "扫码插件,支持识别二维码、条码、多个二维码,连续扫码、相册图片识别、手动聚焦缩放功能、相机自动缩放", + "keywords": [ + "扫码", + "", + "条码", + "", + "二维码", + "", + "谷歌扫码", + "连续扫码" +], + "repository": "", + "engines": { + "HBuilderX": "^4.57", + "uni-app": "^4.66", + "uni-app-x": "^4.66" + }, + "dcloudext": { + "type": "uts", + "sale": { + "regular": { + "price": "50.00" + }, + "sourcecode": { + "price": "398.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "相机、相册" + }, + "npmurl": "", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "√", + "aliyun": "√", + "alipay": "√" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "vue": "-", + "nvue": "-", + "android": { + "extVersion": "", + "minVersion": "21" + }, + "ios": { + "extVersion": "", + "minVersion": "15" + }, + "harmony": "-" + }, + "mp": { + "weixin": "-", + "alipay": "-", + "toutiao": "-", + "baidu": "-", + "kuaishou": "-", + "jd": "-", + "harmony": "-", + "qq": "-", + "lark": "-", + "xhs": "-" + }, + "quickapp": { + "huawei": "-", + "union": "-" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": { + "extVersion": "", + "minVersion": "21" + }, + "ios": { + "extVersion": "", + "minVersion": "15" + }, + "harmony": { + "extVersion": "", + "minVersion": "11" + } + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/xwq-mlkit-scan-code/readme.md b/uni_modules/xwq-mlkit-scan-code/readme.md new file mode 100644 index 0000000..0b9d863 --- /dev/null +++ b/uni_modules/xwq-mlkit-scan-code/readme.md @@ -0,0 +1,373 @@ +# 插件使用说明文档 + +注意! + +插件需要打自定义基座运行! + +插件需要打自定义基座运行! + +插件需要打自定义基座运行! + +#### 插件说明 +``` +本插件是封装了谷歌mlkit条码识别功能,支持多种条码类型扫码, +识别速度和准确率杠杠的,可以支持多个二维码识别,识别成功会有提示音和震动效果,类似wx扫码。 +``` + +IOS端注意!,不支持摄像头切换,用法参考后面的用例(扫码插件支持的ios版本是>=15.5) + +鸿蒙端注意:鸿蒙使用的是官方默认扫码界面UI,不支持自定义界面内容,只能单码识别,不支持连续扫码 + +#### 扫码类型:支持文本、链接、电话、邮件、WIFI等通用类型条码 +``` +type CodeType = 'text'| 'url'| 'wifi'| 'phone'| 'sms' +| 'email' +| 'contact' +| 'geo' +| 'calendar' +| 'driverLicense' +| 'isbn' +| 'product'; +``` +#### 支持扫码格式列表,默认支持全部格式,可以设置单个或多个扫码格式类型,不设置默认是0,支持全部扫码格式 +------------------ + +* 1----->FORMAT_CODE_128 +* 2----->FORMAT_CODE_39 +* 4----->FORMAT_CODE_93 +* 8----->FORMAT_CODABAR +* 32---->FORMAT_EAN_13 +* 64---->FORMAT_EAN_8) +* 128--> FORMAT_ITF) 二维码 +* 256--> FORMAT_QR_CODE 二维码 +* 512--->FORMAT_UPC_A +* 1024-->FORMAT_UPC_E +* 2048-->FORMAT_PDF417 +* 16---->FORMAT_DATA_MATRIX +* 4096-->FORMAT_AZTEC + +-------------- +* 参数说明 + +| 属性 | 类型 | 默认值 | 必填 | 描述 | +|-- |-- |-- |-- |-- | +|cameraType |string |BACK |N |开启前置摄像头,不设置默认使用后置摄像头,当设备只有一个摄像头,该设置无效,会自动取可用列表的摄像头 | +|continuous |boolean |false |N |设为true即可开启连续扫码,默认不开启 | +|continuousDelay |number |800 |N |连续扫码场景,间隔时间 | +|autoZoom |boolean |false |N |开启相机自动缩放,默认不开启,只限非连续扫码模式下使用 | +|styleFollowIos |boolean |true |N |页面样式是否跟随IOS端,默认true全屏模式 | +|showLamplight |boolean |true |N |隐藏/显示灯光操作,默认显示 | +|showPhotoAlbum |boolean |true |N |隐藏/显示相册操作,默认显示 | +|scanBox |boolean |false |N |中间区域扫码模式,默认关闭,(注意:如果开启此模式,styleFollowIos必须配置且为false) | +|scanBoxTitle |string |'将码放入取景框,即可自动扫描' |N |中间区域扫码模式标题,只有scanBox为true生效 | +|scanBoxTitleColor |string |'#ffffff' |N |中间区域扫码模式标题颜色,只有scanBox为true生效 | +|scanBoxTitleSize |number |16 |N |中间区域扫码模式标题大小,只有scanBox为true生效 | +|scanBoxHeight |number |540 |N |中间区域扫码框的高度,只有scanBox为true生效 | +|formatsVal |string |'0' |N |设置扫码的制式,默认为'0',支持全部制式 | +|markeTitle |string |'#ffffff' |N |设置扫码页底部识别中的提示文字 | +|showToast |boolean |false |N |二维码识别成功显示toast(只针对连续扫码生效) | +|showToastText |string |'自定义扫码成功提示' |N |设置连续扫码场景成功提示语 | +|lightOnText |string |'灯光打开' |N |自定义打开灯光文案 | +|lightOffText |string |'灯光关闭' |N |自定义关闭灯光文案 | +|photoText |string |'自定义相册文字' |N |相册底部文案(只针对安卓不跟随IOS端界面样式有效) | +|moreQrCodeSelectText |string |'识别到多个二维码,请选择一个打开' |N |多个二维码选择提示文案 | +|moreQrCodeSelectTextColor |string |'#ffffff' |N |多个二维码选择提示文案颜色 | +|moreQrCodeSelectTextSize |number |16 |N |多个二维码选择提示文案大小 | +|outputAllCodeData |boolean |false |N |开启后,直接返回扫码数据,获取返回值内容需要取optionArr字段,默认关闭(只针对全屏扫码且非连续扫码有效) | +|customFailToatText|string|未识别到二维码|N|未识别到二维码时提示内容| + +#### 识别成功回调参数说明 +```html +CallbackValType:{ + type --- 识别码内容类型 例如文本-text 链接-url 商品-product + option ----{ + textVal?:string ------- 文本值 + url?:string --------- 链接 + phone?:string -------- 手机号 + proNumber?:string ----- 商品编号 + } + optionArr ---- 当初始化配置outputAllCodeData设置为true时,该字段才有值,内容字段和option字段一致 + scanCodeType ----- 识别码为二维码/条形码 1- 二维码 2- 条形码 0- 未知 (当outputAllCodeData设置为true时,该字段会包含在optionArr的每个子项中) +} +``` + +------------ +#### 页面调用插件方式 + + + +* uniapp的使用方式 + +```html + + + + +``` + +* uniappX的使用方式 + +```html + + + + +``` + +### IOS端UniappX项目中使用 +```html + + + + +``` + + +### 在鸿蒙端使用用例(注意:鸿蒙使用的是官方默认扫码界面,不能自定义界面内容,只能单码识别,不支持连续扫码) +```html + + +