明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 756|回复: 4

(WEB端实现CAD功能)在线CAD绘制条形码、二维码的教程

  [复制链接]
发表于 2025-1-18 17:28:17 | 显示全部楼层 |阅读模式
本帖最后由 MxDraw 于 2025-1-18 17:30 编辑

一、条形码绘制
1. 原理
绘制条形码需要根据不同的应用场景选择适当的条形码标准,如常见的 codabar CODE30CODE128每一种条形码标准都有它特定的数据编码规则,调用这些编码规则进行数据编码时会将数据字符按照所选编码规则转换成条和空的组合(一组二进制数据)。不同的条形码标准使用不同的编码规则来表示09的数字或26个英文字母。
其中,为了确保扫描的准确性,条形码中还包括一个校验字符。这个字符通过特定的算法计算得出,用于检验整个条形码的准确性。在生成目标条形码时需对目标内容进行校验,若目标内容符合条形码的编码要求则再进行下一步的绘制。

2. mxcad实现绘制条形码
根据上述条形码绘制原理可知,只要我们能够知道条形码的编码规则将条形码内容转换为一串二进制数据并根据二进制数据的具体值确定条形码条、空的组合,我们就可以在 mxcad 中通过填充实体绘制出条形码。为方便后续对条形码的管理和扩展,我们可以将其绘制为[自定义实体McDbCustomEntity]并为其添加自定义属性。

1)条形码编码规则编写,下面以CODE39为例:
  1. class Barcode{
  2.     constructor(data, options){
  3.         this.data = data;
  4.         this.text = options.text || data;
  5.         this.options = options;
  6.     }
  7. }
  8. class CODE39 extends Barcode {
  9.     constructor(data, options){
  10.         data = data.toUpperCase();
  11.         // Calculate mod43 checksum if enabled
  12.         if(options.mod43){
  13.             data += getCharacter(mod43checksum(data));
  14.         }
  15.         super(data, options);
  16.     }
  17.     encode(){
  18.         // First character is always a *
  19.         var result = getEncoding("*");
  20.         // Take every character and add the binary representation to the result
  21.         for(let i = 0; i < this.data.length; i++){
  22.             result += getEncoding(this.data[i]) + "0";
  23.         }
  24.         // Last character is always a *
  25.         result += getEncoding("*");
  26.         return {
  27.             data: result,
  28.             text: this.text
  29.         };
  30.     }
  31.     valid(){
  32.         return this.data.search(/^[0-9A-Z\-\.\ \$\/\+\%]+$/) !== -1;
  33.     }
  34. }
  35. // All characters. The position in the array is the (checksum) value
  36. var characters = [
  37.     "0", "1", "2", "3",
  38.     "4", "5", "6", "7",
  39.     "8", "9", "A", "B",
  40.     "C", "D", "E", "F",
  41.     "G", "H", "I", "J",
  42.     "K", "L", "M", "N",
  43.     "O", "P", "Q", "R",
  44.     "S", "T", "U", "V",
  45.     "W", "X", "Y", "Z",
  46.     "-", ".", " ", "$",
  47.     "/", "+", "%", "*"
  48. ];
  49. // The decimal representation of the characters, is converted to the
  50. // corresponding binary with the getEncoding function
  51. var encodings = [
  52.     20957, 29783, 23639, 30485,
  53.     20951, 29813, 23669, 20855,
  54.     29789, 23645, 29975, 23831,
  55.     30533, 22295, 30149, 24005,
  56.     21623, 29981, 23837, 22301,
  57.     30023, 23879, 30545, 22343,
  58.     30161, 24017, 21959, 30065,
  59.     23921, 22385, 29015, 18263,
  60.     29141, 17879, 29045, 18293,
  61.     17783, 29021, 18269, 17477,
  62.     17489, 17681, 20753, 35770
  63. ];
  64. // Get the binary representation of a character by converting the encodings
  65. // from decimal to binary
  66. function getEncoding(character){
  67.     return getBinary(characterValue(character));
  68. }
  69. function getBinary(characterValue){
  70.     return encodings[characterValue].toString(2);
  71. }
  72. function getCharacter(characterValue){
  73.     return characters[characterValue];
  74. }
  75. function characterValue(character){
  76.     return characters.indexOf(character);
  77. }
  78. function mod43checksum(data){
  79.     var checksum = 0;
  80.     for(let i = 0; i < data.length; i++){
  81.         checksum += characterValue(data[i]);
  82.     }
  83.     checksum = checksum % 43;
  84.     return checksum;
  85. }
  86. export {CODE39};
复制代码
更多编码规则可参考开源条形码jsJsBarCode

2)实现自定义实体
  1. import { McGeVector3d, McDbHatch, McGePoint3d, McGePoint3dArray, McDbCustomEntity, IMcDbDwgFiler, MxCADWorldDraw, McDbEntity, McDbText, McDb, MxCpp, McGeMatrix3d } from 'mxcad';
  2. import Barcode from './';// 引入条形码类型
  3. // 自定义条形码
  4. class McDbTestBarCode extends McDbCustomEntity {
  5.     /** 条形码位置 */
  6.     private position: McGePoint3d = new McGePoint3d();
  7.     /** 字高  */
  8.     private textHeight: number = 120;
  9.     /** 条形码信息文字 */
  10.     private text: string = '';
  11.     // 条形码高度
  12.     private codeHeight: number = 300;
  13.     // 条形码宽度
  14.     private codeWidth: number = 10;
  15.     // 条形码类型
  16.     private codeType: string = 'CODE39';
  17.     // 条形码内容设置
  18.     private codeContent: string = 'ABCDEFG';
  19.     // 是否显示条形码文字内容
  20.     private showText: boolean = false;
  21.     constructor(imp?: any) {
  22.         super(imp);
  23.     }
  24.     public create(imp: any) {
  25.         return new McDbTestBarCode(imp)
  26.     }
  27.     /** 获取类名 */
  28.     public getTypeName(): string {
  29.         return "McDbTestBarCode";
  30.     }
  31.     //设置或获取基点
  32.     public set barCodePos(val: McGePoint3d) {
  33.         this.position = val.clone();
  34.     }
  35.     public get barCodePos(): McGePoint3d {
  36.         return this.position;
  37.     }
  38.     //设置或获取条形码文字
  39.     public set barCodeText(val: string) {
  40.         this.text = val;
  41.     }
  42.     public get barCodeText(): string {
  43.         return this.text;
  44.     }
  45.     //设置或获取条形码高度
  46.     public set barCodeHeight(val: number) {
  47.         this.codeHeight = val;
  48.     }
  49.     public get barCodeHeight(): number {
  50.         return this.codeHeight;
  51.     }
  52.     //设置或获取条形码类型
  53.     public set barCodeType(val: string) {
  54.         this.codeType = val;
  55.     }
  56.     public get barCodeType(): string {
  57.         return this.codeType;
  58.     }
  59.     //设置或获取条形码宽度
  60.     public set barCodeWidth(val: number) {
  61.         this.codeWidth = val;
  62.     }
  63.     public get barCodeWidth(): number {
  64.         return this.codeWidth;
  65.     }
  66.     // 设置或获取条形码文字高度
  67.     public set barCodeTextHeight(val: number) {
  68.         this.textHeight = val;
  69.     }
  70.     public get barCodeHeigth(): number {
  71.         return this.textHeight;
  72.     }
  73.     // 设置或获取是否显示条形码文字内容
  74.     public set barCodeShowText(val: boolean) {
  75.         this.showText = val;
  76.     }
  77.     public get barCodeShowText(): boolean {
  78.         return this.showText;
  79.     }
  80.     // 设置或获取条形码文字内容
  81.     public set barCodeContent(val: string) {
  82.         this.codeContent = val;
  83.     }
  84.     public get barCodeContent(): string {
  85.         return this.codeContent;
  86.     }
  87.     /** 读取数据 */
  88.     public dwgInFields(filter: IMcDbDwgFiler): boolean {
  89.         this.position = filter.readPoint("position").val;
  90.         this.codeWidth = filter.readDouble("codeWidth").val;
  91.         this.codeHeight = filter.readDouble("codeHeight").val;
  92.         this.textHeight = filter.readDouble("textHeight").val;
  93.         this.text = filter.readString("text").val;
  94.         this.codeType = filter.readString("codeType").val;
  95.         this.codeContent = filter.readString("codeContent").val;
  96.         const isShowText = filter.readLong("showText").val;
  97.         this.showText = isShowText ? true : false;
  98.         return true;
  99.     }
  100.     /** 写入数据 */
  101.     public dwgOutFields(filter: IMcDbDwgFiler): boolean {
  102.         filter.writePoint("position", this.position);
  103.         filter.writeDouble("codeWidth", this.codeWidth);
  104.         filter.writeDouble("codeHeight", this.codeHeight);
  105.         filter.writeString("text", this.text);
  106.         filter.writeDouble("textHeight", this.textHeight);
  107.         filter.writeString("codeType", this.codeType);
  108.         filter.writeString("codeContent", this.codeContent);
  109.         const isShowText = this.showText ? 1 : 0;
  110.         filter.writeLong("showText", isShowText);
  111.         return true;
  112.     }
  113.     /** 移动夹点 */
  114.     public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
  115.         this.assertWrite();
  116.         if (iIndex === 0) {
  117.             this.position.x += dXOffset;
  118.             this.position.y += dYOffset;
  119.             this.position.z += dZOffset;
  120.         }
  121.     };
  122.     /** 获取夹点 */
  123.     public getGripPoints(): McGePoint3dArray {
  124.         let ret = new McGePoint3dArray();
  125.         ret.append(this.position);
  126.         return ret;
  127.     };
  128.     /** 动态绘制 */
  129.     public worldDraw(draw: MxCADWorldDraw): void {
  130.         const code = new Barcode[this.codeType](this.codeContent, {flat: true});
  131.         if (!code.valid()) return alert('条形码类型与内容不匹配!请重新设置!');
  132.         let encoded = code.encode();
  133.         const v = McGeVector3d.kYAxis.clone().mult(this.codeHeight);
  134.         const _v = McGeVector3d.kXAxis.clone().mult(this.codeWidth);
  135.         encoded.data.split('').forEach((val, index) => {
  136.             const solid = new McDbHatch();
  137.             const point1 = new McGePoint3d(this.position.x + index * this.codeWidth, this.position.y, this.position.z);
  138.             const point2 = point1.clone().addvec(v);
  139.             const point3 = point2.clone().addvec(_v);
  140.             const point4 = point1.clone().addvec(_v);
  141.             const points = new McGePoint3dArray([point1, point2, point3, point4]);
  142.             solid.appendLoop(points);
  143.             if (val == '1') {
  144.                 draw.drawEntity(solid);
  145.             }
  146.         })
  147.         if (this.showText) {
  148.             const text = this.getCodeText();
  149.             draw.drawEntity(text);
  150.         }
  151.     };
  152.     // 设置条形码文字实体
  153.     private getCodeText(): McDbEntity {
  154.         if (!this.text) this.text = this.codeContent;
  155.         const text = new McDbText();
  156.         text.textString = this.text;
  157.         text.height = this.textHeight;
  158.         const v = McGeVector3d.kYAxis.clone().negate().mult(this.textHeight * (4 / 3));
  159.         text.position = text.alignmentPoint = this.position.clone().addvec(v);
  160.         text.horizontalMode = McDb.TextHorzMode.kTextLeft;
  161.         return text
  162.     }
  163.     // 编辑变换
  164.     public transformBy(_mat: McGeMatrix3d): boolean {
  165.         this.position.transformBy(_mat);
  166.         return true;
  167.     }
  168. }
3)调用条形码自定义实体McDbTestBarCode绘制条形码
  1. async function Mx_drawBarCode() {
  2.     const mxcad = MxCpp.getCurrentMxCAD();
  3.     mxcad.newFile();
  4.     mxcad.setViewBackgroundColor(255, 255, 255);
  5.     // CODE39 类型条形码
  6.     const barCode = new McDbTestBarCode();
  7.     barCode.barCodePos = new McGePoint3d(100, 100, 0);
  8.     barCode.barCodeShowText = true;
  9.     mxcad.drawEntity(barCode);
  10.     // CODE128 类型条形码
  11.     const barCode2 = new McDbTestBarCode();
  12.     barCode2.barCodeContent = 'A little test!';
  13.     barCode2.barCodeType = 'CODE128';
  14.     barCode2.barCodePos = new McGePoint3d(-2000, 100, 0);
  15.     barCode2.barCodeShowText = true;
  16.     mxcad.drawEntity(barCode2);
  17.     // EAN13 类型条形码
  18.     const barCode3 = new McDbTestBarCode();
  19.     barCode3.barCodeContent = '5901234123457';
  20.     barCode3.barCodeType = 'EAN13';
  21.     barCode3.barCodePos = new McGePoint3d(-2000, -800, 0);
  22.     barCode3.barCodeShowText = true;
  23.     mxcad.drawEntity(barCode3);
  24.     // codabar 类型条形码
  25.     const barCode4 = new McDbTestBarCode();
  26.     barCode4.barCodeContent = 'C1234567890D';
  27.     barCode4.barCodeType = 'codabar';
  28.     barCode4.barCodePos = new McGePoint3d(100, -800, 0);
  29.     barCode4.barCodeShowText = true;
  30.     mxcad.drawEntity(barCode4);
  31.     mxcad.zoomAll();
  32.     mxcad.zoomScale(4);
  33. }
复制代码
4) 绘制效果演示:


二、绘制二维码

1.原理
二维码是一种矩阵式二维条码,它能在水平和垂直两个方向上存储信息。二维码中的原始数据可以是数字、字母、二进制数据或其他字符&#8204;,根据原始数据的类型,选择合适的编码模式。例如,数字数据使用数字模式,字母和数字混合使用alphanumeric模式,其他类型的数据则使用字节模式&#8204;
原始数据经过编码后的数据将放入一个二维矩阵中。这个过程可能需要使用掩模技术,通过应用特定的掩模图案来优化二维码中的黑白点的分布,避免出现与定位标记相似的模式&#8204;,其中, 需要在矩阵的特定区域添加格式化和版本信息,以及必要时添加校正标记&#8204;

2.mxcad 实现绘制二维码
二维码的编码规则我们可以直接借助二维码开源jsQRCode.js ,更多详细内容看参考:https://github.com/davidshimjs/qrcodejs
结合QRcode.js ,我们可以在mxcad中通过填充实体绘制出二维矩阵中的黑白块。为方便后续对二维码的管理和扩展,我们可以将其绘制为[自定义实体McDbCustomEntity]并为其添加自定义属性。
1QRcode.js扩写:
  1. // 增加 QRCode类的 makeMxcadCode 方法
  2. QRCode.prototype.makeMxcadCode = function (sText) {
  3.         this._oQRCode = new QRCodeModel(_getTypeNumber(sText, this._htOption.correctLevel), this._htOption.correctLevel);
  4.         this._oQRCode.addData(sText);
  5.         this._oQRCode.make();
  6.         return this._oDrawing.drawMxcadHatch(this._oQRCode);
  7.     };
复制代码
绘制mxcad填充代码
  1. // 绘制mxcad填充代码(扩写Drawing类)
  2. Drawing.prototype.drawMxcadHatch = function (oQRCode): McDbEntity[] {
  3.     const entityArr = [];
  4.     var _htOption = this._htOption;
  5.     var nCount = oQRCode.getModuleCount();
  6.     var nWidth = _htOption.width / nCount;
  7.     var nHeight = _htOption.height / nCount;
  8.     for (var row = 0; row < nCount; row++) {
  9.         for (var col = 0; col < nCount; col++) {
  10.             var bIsDark = oQRCode.isDark(row, col);
  11.             var nLeft = col * nWidth;
  12.             var nTop = row * nHeight;
  13.             if (bIsDark) {
  14.                 // 矩形填充
  15.                 const pos = new McGePoint3d(nLeft, nTop, 0);
  16.                 const v_y = McGeVector3d.kYAxis.clone().negate().mult(nHeight);
  17.                 const v_x = McGeVector3d.kXAxis.clone().mult(nWidth);
  18.                 const pos1 = pos.clone().addvec(v_y);
  19.                 const pos2 = pos.clone().addvec(v_x);
  20.                 const pos3 = pos.clone().addvec(v_x).addvec(v_y);
  21.                 const solid = new McDbHatch();
  22.                 const ptArr = new McGePoint3dArray([pos, pos1, pos3, pos2]);
  23.                 solid.appendLoop(ptArr);
  24.                 entityArr.push(solid);
  25.             }
  26.         }
  27.     }
  28.     return entityArr;
  29. };<span style="font-family: Calibri; font-size: 10.5pt; background-color: rgb(255, 255, 255);"> </span>
复制代码
2)实现自定义实体
  1. import { MxCpp, McDbCustomEntity, McGePoint3d, IMcDbDwgFiler, McGePoint3dArray, MxCADWorldDraw, McGeMatrix3d, McDbEntity } from "mxcad";
  2. import { QRCode } from './qrCode'
  3. // 自定义二维码实体
  4. class McDbTestQrCode extends McDbCustomEntity {
  5.     /** 二维码的位置 */
  6.     private position: McGePoint3d = new McGePoint3d();
  7.     // 二维码高度
  8.     private codeHeight: number = 300;
  9.     // 二维码宽度
  10.     private codeWidth: number = 10;
  11.     // 二维码内容设置
  12.     private codeContent: string = 'https://demo.mxdraw3d.com:3000/mxcad/';
  13.     constructor(imp?: any) {
  14.         super(imp);
  15.     }
  16.     public create(imp: any) {
  17.         return new McDbTestQrCode(imp)
  18.     }
  19.     /** 获取类名 */
  20.     public getTypeName(): string {
  21.         return "McDbTestQrCode";
  22.     }
  23.     //设置或获取基点
  24.     public set qrCodePos(val: McGePoint3d) {
  25.         this.position = val.clone();
  26.     }
  27.     public get qrCodePos(): McGePoint3d {
  28.         return this.position;
  29.     }
  30.     //设置或获取码高度
  31.     public set qrCodeHeight(val: number) {
  32.         this.codeHeight = val;
  33.     }
  34.     public get qarCodeHeight(): number {
  35.         return this.codeHeight;
  36.     }
  37.     //设置或获取码宽度
  38.     public set qrCodeWidth(val: number) {
  39.         this.codeWidth = val;
  40.     }
  41.     public get qrCodeWidth(): number {
  42.         return this.codeWidth;
  43.     }
  44.     // 设置或获取二维码内容
  45.     public set qrCodeContent(val: string) {
  46.         this.codeContent = val;
  47.     }
  48.     public get qrCodeContent(): string {
  49.         return this.codeContent;
  50.     }
  51.     /** 读取数据 */
  52.     public dwgInFields(filter: IMcDbDwgFiler): boolean {
  53.         this.position = filter.readPoint("position").val;
  54.         this.codeWidth = filter.readDouble("codeWidth").val;
  55.         this.codeHeight = filter.readDouble("codeHeight").val;
  56.         this.codeContent = filter.readString("codeContent").val;
  57.         return true;
  58.     }
  59.     /** 写入数据 */
  60.     public dwgOutFields(filter: IMcDbDwgFiler): boolean {
  61.         filter.writePoint("position", this.position);
  62.         filter.writeDouble("codeWidth", this.codeWidth);
  63.         filter.writeDouble("codeHeight", this.codeHeight);
  64.         filter.writeString("codeContent", this.codeContent);
  65.         return true;
  66.     }
  67.     /** 移动夹点 */
  68.     public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
  69.         this.assertWrite();
  70.         if (iIndex === 0) {
  71.             this.position.x += dXOffset;
  72.             this.position.y += dYOffset;
  73.             this.position.z += dZOffset;
  74.         }
  75.     };
  76.     /** 获取夹点 */
  77.     public getGripPoints(): McGePoint3dArray {
  78.         let ret = new McGePoint3dArray();
  79.         ret.append(this.position);
  80.         return ret;
  81.     };
  82.     /** 动态绘制 */
  83.     public worldDraw(draw: MxCADWorldDraw): void {
  84.         const qrcode = new QRCode('', {
  85.             width: this.codeWidth,
  86.             height: this.codeHeight
  87.         });
  88.         const objArr = qrcode.makeMxcadCode(this.codeContent);
  89.         objArr.forEach((obj: McDbEntity) => {
  90.             const entity = obj.clone() as McDbEntity;
  91.             entity.move(new McGePoint3d(0, 0, 0), this.position);
  92.             draw.drawEntity(entity);
  93.         })
  94.     };
  95.     // 编辑变换
  96.     public transformBy(_mat: McGeMatrix3d): boolean {
  97.         this.position.transformBy(_mat);
  98.         return true;
  99.     }
  100. }
3)调用二维码自定义实体McDbTestQrCode绘制二维码
  1. //画二维码
  2. async function Mx_drawQrCode() {
  3.     const mxcad = MxCpp.getCurrentMxCAD();
  4.     mxcad.newFile();
  5.     const qrcode = new McDbTestQrCode();
  6.     qrcode.qrCodePos = new McGePoint3d(1000, 1000, 0);
  7.     qrcode.qrCodeContent = 'https://demo.mxdraw3d.com:3000/mxcad/';
  8.     qrcode.qrCodeWidth = 1500;
  9.     qrcode.qrCodeHeight = 1500;
  10.     mxcad.drawEntity(qrcode);
  11.     mxcad.zoomAll();
  12. };
复制代码
4绘制效果演示:


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复

使用道具 举报

发表于 2025-1-24 13:27:04 | 显示全部楼层
实在是令人钦佩不已。
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
xiaolong1487 发表于 2025-1-24 13:27
实在是令人钦佩不已。

谢谢关注
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-2-22 02:24 , Processed in 0.167820 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表