Merge branch 'dev-redux' of https://github.com/ciaochaos/qrbtf into dev-redux
This commit is contained in:
commit
e141541287
|
@ -8091,6 +8091,11 @@
|
||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jsqr": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npm.taobao.org/jsqr/download/jsqr-1.3.1.tgz",
|
||||||
|
"integrity": "sha1-UVp2bliwDIAULzotxLh1EQDO7c8="
|
||||||
|
},
|
||||||
"jsx-ast-utils": {
|
"jsx-ast-utils": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npm.taobao.org/jsx-ast-utils/download/jsx-ast-utils-2.2.3.tgz",
|
"resolved": "https://registry.npm.taobao.org/jsx-ast-utils/download/jsx-ast-utils-2.2.3.tgz",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.3.2",
|
"@testing-library/react": "^9.3.2",
|
||||||
"@testing-library/user-event": "^7.1.2",
|
"@testing-library/user-event": "^7.1.2",
|
||||||
|
"jsqr": "^1.3.1",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-color": "^2.18.1",
|
"react-color": "^2.18.1",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
.Qr-titled {
|
.Qr-titled {
|
||||||
background-color: #f5f5f7;
|
background-color: #f5f5f7;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -461,11 +462,61 @@ a:hover {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Qr-article {
|
||||||
|
word-wrap: break-word;
|
||||||
|
margin-top: calc((10px + 1vmin) * 2);
|
||||||
|
margin-bottom: calc((10px + 2vmin) * 2);
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article p {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.7em;
|
||||||
|
color: #636366;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article p b {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article p a {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 1px 0;
|
||||||
|
color: #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article p a:hover {
|
||||||
|
color: #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article h2 {
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.7em;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-top: 1.5em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 500px) {
|
||||||
.note-font {
|
.note-font {
|
||||||
color: #1D1D1F;
|
color: #1D1D1F;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Qr-article p {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-article h2 {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import '../Qrcode.css';
|
import '../Qrcode.css';
|
||||||
import Footer from "../footer/Footer";
|
import PartFooter from "./PartFooter";
|
||||||
import Header from "../header/Header";
|
import PartHeader from "./PartHeader";
|
||||||
import PartMore from "./PartMore";
|
import PartMore from "./PartMore";
|
||||||
import PartParams from "./PartParams";
|
import PartParams from "./PartParams";
|
||||||
import PartDownloadViewer from "../../containers/app/PartDownloadViewer";
|
import PartDownloadViewer from "../../containers/app/PartDownloadViewer";
|
||||||
|
@ -14,12 +14,12 @@ function App() {
|
||||||
<header className="App-header">
|
<header className="App-header">
|
||||||
<div className="Layout">
|
<div className="Layout">
|
||||||
<div className="Qr-outer">
|
<div className="Qr-outer">
|
||||||
<Header/>
|
<PartHeader/>
|
||||||
<PartStylesViewer/>
|
<PartStylesViewer/>
|
||||||
<PartParams/>
|
<PartParams/>
|
||||||
<PartDownloadViewer/>
|
<PartDownloadViewer/>
|
||||||
<PartMore/>
|
<PartMore/>
|
||||||
<Footer/>
|
<PartFooter/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import '../Qrcode.css';
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear();
|
const currentYear = new Date().getFullYear();
|
||||||
|
|
||||||
const Footer = () => (
|
const PartFooter = () => (
|
||||||
<div className="Qr-titled">
|
<div className="Qr-titled">
|
||||||
<div className="Qr-Centered Qr-footer note-font">
|
<div className="Qr-Centered Qr-footer note-font">
|
||||||
<div>
|
<div>
|
||||||
|
@ -33,4 +33,4 @@ const Footer = () => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default Footer
|
export default PartFooter
|
|
@ -9,7 +9,7 @@ const logoStyle = {
|
||||||
backgroundPosition: 'left'
|
backgroundPosition: 'left'
|
||||||
};
|
};
|
||||||
|
|
||||||
const Header = () => (
|
const PartHeader = () => (
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
<div style={logoStyle}>
|
<div style={logoStyle}>
|
||||||
<h1 className="Qr-title"> </h1>
|
<h1 className="Qr-title"> </h1>
|
||||||
|
@ -19,4 +19,4 @@ const Header = () => (
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default Header
|
export default PartHeader
|
|
@ -7,6 +7,20 @@ const PartMore = () => (
|
||||||
<div className="Qr-Centered title-margin">
|
<div className="Qr-Centered title-margin">
|
||||||
<div className="Qr-s-title">More</div>
|
<div className="Qr-s-title">More</div>
|
||||||
<p className="Qr-s-subtitle">更多</p>
|
<p className="Qr-s-subtitle">更多</p>
|
||||||
|
<div className="Qr-article">
|
||||||
|
<h2>为什么要做一个二维码生成器?</h2>
|
||||||
|
<p>看这里,<a href='https://mp.weixin.qq.com/s/_Oy9I9FqPXhfwN9IUhf6_g' rel="noopener noreferrer" target="_blank">这篇文章</a> 简要介绍了我们的初心与愿景。</p>
|
||||||
|
<h2>这个生成器的特别之处在哪里?</h2>
|
||||||
|
<p>普通的二维码样式单一,不能与环境较好的融合。这一个生成器有着 <b>丰富的参数化样式、基于 SVG 的二维码生成能力</b>,在为我们提供精美样式的同时,不限制参数如数值、颜色、背景图片的选择,又因 SVG 有较好的拓展性,可以完美兼容矢量制图流程。</p>
|
||||||
|
<h2>如何使用?</h2>
|
||||||
|
<p>从输入 URL 开始。没有确认框,没有额外的页面,选择样式后自动更新,调整参数后下载即可。</p>
|
||||||
|
<h2>我应该下载 SVG 还是 JPG?</h2>
|
||||||
|
<p>这个工具开发的初衷之一就是便利设计师将其纳入自己的工作流程中。SVG 是一个优秀的、标准的矢量图片格式,各大设计软件如 Adobe Illustrator、Sketch 等都对 SVG 有着很好的支持。用户可以在下载 SVG 后导入这些软件进行二次加工,如删除中央的信息点 <b>放入自己的 Logo</b> 等。如果需要直接分享二维码图像,请直接下载 JPG 格式。</p>
|
||||||
|
<h2>使用遇到了问题,怎么反馈?</h2>
|
||||||
|
<p>我们是两位大一的学生,忙于学业,可能在设计与开发的过程中有一些疏漏,敬请谅解。如果遇到浏览器兼容问题,请暂时选择更换软件或设备尝试。经常有人问,怎么把已有的公众号二维码上传,很抱歉的是,目前我们并没有开发这个功能,将来一定实现,如有需要请暂时使用第三方软件解码。也有人问,为什么电脑端右边的样式没显示全,不是 bug,只是我们懒得做切换滑动按钮,目前请按住 Shift 使用滚轮在样式区域滚动,一定能行。</p>
|
||||||
|
<p>请注意,应用并不能保证二维码时刻可被识别,需要多加测试。</p>
|
||||||
|
<p>如果你有兴趣和我们一起玩这个项目,<b>设计样式、开发应用</b>,欢迎点击下方的按钮加微信联系我们!</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="Qr-Centered btn-row">
|
<div className="Qr-Centered btn-row">
|
||||||
<div className="div-btn">
|
<div className="div-btn">
|
||||||
|
@ -14,8 +28,7 @@ const PartMore = () => (
|
||||||
<LinkButton href={"https://www.yuque.com/qrbtf/topics"} value={"问题反馈"} />
|
<LinkButton href={"https://www.yuque.com/qrbtf/topics"} value={"问题反馈"} />
|
||||||
</div>
|
</div>
|
||||||
<div className="div-btn">
|
<div className="div-btn">
|
||||||
<LinkButton href={"https://www.yuque.com/qrbtf/docs/dev"} value={"开发与设计"} />
|
<LinkButton href={"https://www.yuque.com/qrbtf/docs/coop"} value={"合作咨询"} />
|
||||||
<LinkButton href={"https://www.yuque.com/qrbtf/docs/coop"} value={"商业合作"} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import {defaultViewBox, rand} from "../../utils/util";
|
import {defaultViewBox, rand} from "../../utils/util";
|
||||||
import {ParamTypes} from "../../constant/ParamTypes";
|
|
||||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints(qrcode, params) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
|
@ -9,10 +9,12 @@ function listPoints(qrcode, params) {
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
const typeTable = getTypeTable(qrcode);
|
const typeTable = getTypeTable(qrcode);
|
||||||
const pointList = new Array(nCount);
|
const pointList = new Array(nCount);
|
||||||
let alignType = params[1];
|
let contrast = params[1];
|
||||||
let timingType = params[2];
|
let exposure = params[2];
|
||||||
let otherColor = params[3];
|
let alignType = params[3];
|
||||||
let posColor = params[4];
|
let timingType = params[4];
|
||||||
|
let otherColor = params[5];
|
||||||
|
let posColor = params[6];
|
||||||
|
|
||||||
let id = 0;
|
let id = 0;
|
||||||
for (let x = 0; x < nCount; x++) {
|
for (let x = 0; x < nCount; x++) {
|
||||||
|
@ -74,6 +76,16 @@ function getParamInfo() {
|
||||||
key: '背景图片',
|
key: '背景图片',
|
||||||
default: data,
|
default: data,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: ParamTypes.TEXT_EDITOR,
|
||||||
|
key: '对比度',
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ParamTypes.TEXT_EDITOR,
|
||||||
|
key: '曝光',
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: ParamTypes.SELECTOR,
|
type: ParamTypes.SELECTOR,
|
||||||
key: '小定位点样式',
|
key: '小定位点样式',
|
||||||
|
@ -114,7 +126,7 @@ export function getViewBox(qrcode) {
|
||||||
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
|
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGrayPointList(imgBase64, size, black, white) {
|
function getGrayPointList(params, size, black, white) {
|
||||||
let canvas = document.createElement('canvas');
|
let canvas = document.createElement('canvas');
|
||||||
let ctx = canvas.getContext('2d');
|
let ctx = canvas.getContext('2d');
|
||||||
let img = document.createElement('img');
|
let img = document.createElement('img');
|
||||||
|
@ -122,7 +134,9 @@ function getGrayPointList(imgBase64, size, black, white) {
|
||||||
canvas.style.imageRendering = 'pixelated';
|
canvas.style.imageRendering = 'pixelated';
|
||||||
size *= 3;
|
size *= 3;
|
||||||
|
|
||||||
img.src = imgBase64;
|
img.src = params[0];
|
||||||
|
let contrast = params[1]/100;
|
||||||
|
let exposure = params[2]/100;
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
canvas.width = size;
|
canvas.width = size;
|
||||||
|
@ -135,7 +149,7 @@ function getGrayPointList(imgBase64, size, black, white) {
|
||||||
let imageData = ctx.getImageData(x, y, 1, 1);
|
let imageData = ctx.getImageData(x, y, 1, 1);
|
||||||
let data = imageData.data;
|
let data = imageData.data;
|
||||||
let gray = gamma(data[0], data[1], data[2]);
|
let gray = gamma(data[0], data[1], data[2]);
|
||||||
if (Math.random() > gray / 255 && ( x % 3 !== 1 || y % 3 !== 1 ) ) gpl.push(<use key={"g_" + x + "_" + y} x={x} y={y} xlinkHref={black} />);
|
if (Math.random() > ((gray / 255) + exposure - 0.5) * (contrast + 1) + 0.5 && ( x % 3 !== 1 || y % 3 !== 1 ) ) gpl.push(<use key={"g_" + x + "_" + y} x={x} y={y} xlinkHref={black} />);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(gpl);
|
resolve(gpl);
|
||||||
|
@ -144,8 +158,7 @@ function getGrayPointList(imgBase64, size, black, white) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const RendererResImage = ({qrcode, params, setParamInfo}) => {
|
const RendererResImage = ({qrcode, params, setParamInfo}) => {
|
||||||
let otherColor = params[3];
|
let otherColor = params[5];
|
||||||
let posColor = params[4];
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setParamInfo(getParamInfo());
|
setParamInfo(getParamInfo());
|
||||||
|
@ -153,8 +166,8 @@ const RendererResImage = ({qrcode, params, setParamInfo}) => {
|
||||||
|
|
||||||
const [gpl, setGPL] = useState([]);
|
const [gpl, setGPL] = useState([]);
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
getGrayPointList(params[0], qrcode.getModuleCount(), "#S-black", "#S-white").then(res => setGPL(res));
|
getGrayPointList(params, qrcode.getModuleCount(), "#S-black", "#S-white").then(res => setGPL(res));
|
||||||
}, [setGPL, params[0], qrcode])
|
}, [setGPL, params, qrcode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={getViewBox(qrcode)} fill="white"
|
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={getViewBox(qrcode)} fill="white"
|
||||||
|
|
|
@ -3,5 +3,5 @@ export const actionTypes = {
|
||||||
CHANGE_STYLE: 'CHANGE_STYLE',
|
CHANGE_STYLE: 'CHANGE_STYLE',
|
||||||
CHANGE_CORRECT_LEVEL: 'CHANGE_CORRECT_LEVEL',
|
CHANGE_CORRECT_LEVEL: 'CHANGE_CORRECT_LEVEL',
|
||||||
CREATE_PARAM: 'CREATE_PARAM',
|
CREATE_PARAM: 'CREATE_PARAM',
|
||||||
CHANGE_PARAM: 'CHANGE_PARAM'
|
CHANGE_PARAM: 'CHANGE_PARAM',
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import {genQRInfo} from "../../actions";
|
import {genQRInfo} from "../../actions";
|
||||||
import React from "react";
|
import React, {useRef} from "react";
|
||||||
|
import {isPicture} from "../../utils/util";
|
||||||
|
import {decodeData} from "../../utils/qrcodeHandler";
|
||||||
|
|
||||||
const InputText = ({dispatch}) => (
|
const InputText = ({dispatch}) => {
|
||||||
|
const textRef = useRef();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
<input
|
<input
|
||||||
className="Qr-input big-input"
|
className="Qr-input big-input"
|
||||||
placeholder="Input your URL here"
|
placeholder="Input your URL here"
|
||||||
|
ref={textRef}
|
||||||
onBlur={e => dispatch(genQRInfo(e.target.value))}
|
onBlur={e => dispatch(genQRInfo(e.target.value))}
|
||||||
onKeyPress={(e) => {
|
onKeyPress={(e) => {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
|
@ -14,6 +21,35 @@ const InputText = ({dispatch}) => (
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
<label
|
||||||
|
htmlFor="image_scanner"
|
||||||
|
className="dl-btn"
|
||||||
|
style={{textAlign: "center"}}
|
||||||
|
>
|
||||||
|
扫描图片
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="image_scanner"
|
||||||
|
hidden={true}
|
||||||
|
accept=".jpg, .jpeg, .png"
|
||||||
|
onClick={(e) => e.target.value = null}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (e.target.files.length > 0) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (isPicture(file)) {
|
||||||
|
decodeData(file).then((res) => {
|
||||||
|
if (res) {
|
||||||
|
textRef.current.value = res.data;
|
||||||
|
console.log(res.data)
|
||||||
|
dispatch(genQRInfo(res.data))
|
||||||
|
}
|
||||||
|
}).catch(console.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</React.Fragment>);
|
||||||
|
}
|
||||||
|
|
||||||
export default connect()(InputText);
|
export default connect()(InputText);
|
||||||
|
|
|
@ -1,41 +1,36 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PartDownload from "../../components/app/PartDownload";
|
import PartDownload from "../../components/app/PartDownload";
|
||||||
import React from "react";
|
|
||||||
import {saveImg, saveSvg} from "../../utils/downloader";
|
import {saveImg, saveSvg} from "../../utils/downloader";
|
||||||
import ReactDOMServer from "react-dom/server";
|
|
||||||
import {increaseDownloadData, recordDownloadDetail} from "../../api/db";
|
import {increaseDownloadData, recordDownloadDetail} from "../../api/db";
|
||||||
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
||||||
|
|
||||||
function saveEl(state, type) {
|
function saveDB(state, type) {
|
||||||
const el = React.createElement(state.rendererType, {
|
|
||||||
qrcode: state.qrcode,
|
|
||||||
params: state.paramValue[state.selectedIndex],
|
|
||||||
setParamInfo: () => {}
|
|
||||||
});
|
|
||||||
increaseDownloadData(state.value)
|
increaseDownloadData(state.value)
|
||||||
recordDownloadDetail({
|
recordDownloadDetail({
|
||||||
text: state.textUrl,
|
text: state.textUrl,
|
||||||
value: state.value,
|
value: state.value,
|
||||||
type: type,
|
type: type,
|
||||||
params: state.paramInfo[state.selectedIndex].map((item, index) => {
|
params: state.paramInfo[state.selectedIndex].map((item, index) => {
|
||||||
|
const value = getParamDetailedValue(item, state.paramValue[state.selectedIndex][index])
|
||||||
|
if (typeof value != "string" || value.length <= 128) {
|
||||||
return {
|
return {
|
||||||
key: item.key,
|
key: item.key,
|
||||||
value: getParamDetailedValue(item, state.paramValue[state.selectedIndex][index])
|
value: value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
history: state.history
|
history: state.history
|
||||||
});
|
});
|
||||||
return el;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
value: state.value,
|
value: state.value,
|
||||||
onSvgDownload: () => {
|
onSvgDownload: () => {
|
||||||
// saveSvg(state.value, ReactDOMServer.renderToString(saveEl(state, 'svg')))
|
|
||||||
saveSvg(state.value, outerHtml(state.selectedIndex))
|
saveSvg(state.value, outerHtml(state.selectedIndex))
|
||||||
|
saveDB(state, 'svg')
|
||||||
},
|
},
|
||||||
onJpgDownload: () => {
|
onJpgDownload: () => {
|
||||||
// return saveImg(state.value, ReactDOMServer.renderToString(saveEl(state, 'jpg')), 1500, 1500)
|
saveDB(state, 'jpg')
|
||||||
return saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500)
|
return saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,17 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {changeParam} from "../../actions";
|
import {changeParam} from "../../actions";
|
||||||
import ParamUpload from "../../components/param/ParamUpload";
|
import ParamUpload from "../../components/param/ParamUpload";
|
||||||
import {toBase64} from "../../utils/util";
|
import {isPicture, toBase64} from "../../utils/util";
|
||||||
|
|
||||||
const fileTypes =[
|
|
||||||
'image/jpeg',
|
|
||||||
'image/pjpeg',
|
|
||||||
'image/png'
|
|
||||||
]
|
|
||||||
|
|
||||||
function validFileType(file) {
|
|
||||||
return fileTypes.includes(file.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => ({
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
rendererIndex: ownProps.rendererIndex,
|
rendererIndex: ownProps.rendererIndex,
|
||||||
|
@ -24,7 +14,7 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
onChange: (e) => {
|
onChange: (e) => {
|
||||||
if (e.target.files.length > 0) {
|
if (e.target.files.length > 0) {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (validFileType(file)) {
|
if (isPicture(file)) {
|
||||||
toBase64(file, 500, 500).then(res => {
|
toBase64(file, 500, 500).then(res => {
|
||||||
dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, res))
|
dispatch(changeParam(ownProps.rendererIndex, ownProps.paramIndex, res))
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import {connect, useDispatch} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import {changeStyle, createParam} from "../../actions";
|
import {changeStyle} from "../../actions";
|
||||||
import StyleList from "../../components/style/StyleList";
|
import StyleList from "../../components/style/StyleList";
|
||||||
import RendererViewer from "./RendererViewer";
|
import RendererViewer from "./RendererViewer";
|
||||||
import RendererBlank from "../../components/renderer/RendererBlank";
|
|
||||||
import RendererBase from "../../components/renderer/RendererBase";
|
import RendererBase from "../../components/renderer/RendererBase";
|
||||||
import RendererDSJ from "../../components/renderer/RendererDSJ";
|
import RendererDSJ from "../../components/renderer/RendererDSJ";
|
||||||
import RendererRound from "../../components/renderer/RendererRound";
|
import RendererRound from "../../components/renderer/RendererRound";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {getQrcodeData} from "../utils/qrcodeHandler";
|
import {encodeData} from "../utils/qrcodeHandler";
|
||||||
import {actionTypes} from "../constant/ActionTypes";
|
import {actionTypes} from "../constant/ActionTypes";
|
||||||
import {QRBTF_URL} from "../constant/References";
|
import {QRBTF_URL} from "../constant/References";
|
||||||
import RendererBase from "../components/renderer/RendererBase";
|
import RendererBase from "../components/renderer/RendererBase";
|
||||||
|
@ -11,7 +11,7 @@ const initialState = {
|
||||||
correctLevel: 0,
|
correctLevel: 0,
|
||||||
textUrl: QRBTF_URL,
|
textUrl: QRBTF_URL,
|
||||||
history: [],
|
history: [],
|
||||||
qrcode: getQrcodeData({text: QRBTF_URL, correctLevel: 0}),
|
qrcode: encodeData({text: QRBTF_URL, correctLevel: 0}),
|
||||||
paramInfo: new Array(16).fill(new Array(16)),
|
paramInfo: new Array(16).fill(new Array(16)),
|
||||||
paramValue: new Array(16).fill(new Array(16))
|
paramValue: new Array(16).fill(new Array(16))
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export default function appReducer(state = initialState, action) {
|
||||||
if (!text || text.length == 0) text = QRBTF_URL;
|
if (!text || text.length == 0) text = QRBTF_URL;
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
textUrl: text,
|
textUrl: text,
|
||||||
qrcode: getQrcodeData({text: text, correctLevel: state.correctLevel})
|
qrcode: encodeData({text: text, correctLevel: state.correctLevel})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
case actionTypes.CHANGE_STYLE: {
|
case actionTypes.CHANGE_STYLE: {
|
||||||
|
@ -37,7 +37,7 @@ export default function appReducer(state = initialState, action) {
|
||||||
case actionTypes.CHANGE_CORRECT_LEVEL: {
|
case actionTypes.CHANGE_CORRECT_LEVEL: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
correctLevel: parseInt(action.correctLevel),
|
correctLevel: parseInt(action.correctLevel),
|
||||||
qrcode: getQrcodeData({text: state.textUrl, correctLevel: parseInt(action.correctLevel)})
|
qrcode: encodeData({text: state.textUrl, correctLevel: parseInt(action.correctLevel)})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case actionTypes.CREATE_PARAM: {
|
case actionTypes.CREATE_PARAM: {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// http://www.denso-wave.com/qrcode/faqpatent-e.html
|
// http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
/* eslint-disable */
|
||||||
function QR8bitByte(data) {
|
function QR8bitByte(data) {
|
||||||
this.mode = QRMode.MODE_8BIT_BYTE;
|
this.mode = QRMode.MODE_8BIT_BYTE;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
@ -1270,4 +1271,4 @@ QRBitBuffer.prototype = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default QRCode
|
exports.qrcode = QRCode;
|
|
@ -1,4 +1,5 @@
|
||||||
import QRCode from "./qrcode";
|
import { qrcode as QRCodeEncoder } from "./qrcodeEncoder";
|
||||||
|
import jsQR from "jsqr";
|
||||||
|
|
||||||
function extend(target, options) {
|
function extend(target, options) {
|
||||||
for (let name in options) {
|
for (let name in options) {
|
||||||
|
@ -18,7 +19,7 @@ export var QRPointType = {
|
||||||
VERSION: 7
|
VERSION: 7
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getQrcodeData(options) {
|
export function encodeData(options) {
|
||||||
if (!options.text || options.text.length <= 0) return null
|
if (!options.text || options.text.length <= 0) return null
|
||||||
|
|
||||||
options = extend({
|
options = extend({
|
||||||
|
@ -31,7 +32,7 @@ export function getQrcodeData(options) {
|
||||||
foreground : "#000000"
|
foreground : "#000000"
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
let qrcode = new QRCode(options.typeNumber, options.correctLevel)
|
let qrcode = new QRCodeEncoder(options.typeNumber, options.correctLevel)
|
||||||
qrcode.addData(options.text)
|
qrcode.addData(options.text)
|
||||||
qrcode.make()
|
qrcode.make()
|
||||||
|
|
||||||
|
@ -90,3 +91,26 @@ export function getTypeTable(qrcode) {
|
||||||
}
|
}
|
||||||
return typeTable;
|
return typeTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function decodeData(file) {
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
let ctx = canvas.getContext('2d');
|
||||||
|
let img = document.createElement('img');
|
||||||
|
const maxSize = 400;
|
||||||
|
|
||||||
|
img.setAttribute('src', URL.createObjectURL(file));
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
img.onload = () => {
|
||||||
|
let rate = Math.min(img.width, img.height) / maxSize;
|
||||||
|
|
||||||
|
canvas.width = img.width / rate;
|
||||||
|
canvas.height = img.height / rate;
|
||||||
|
|
||||||
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
let result = jsQR(
|
||||||
|
ctx.getImageData(0, 0, canvas.width, canvas.height).data, canvas.width, canvas.height);
|
||||||
|
resolve(result);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
import {ParamTypes} from "../constant/ParamTypes";
|
import {ParamTypes} from "../constant/ParamTypes";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
let seed = 0;
|
let seed = 0;
|
||||||
|
|
||||||
|
const fileTypes =[
|
||||||
|
'image/jpeg',
|
||||||
|
'image/pjpeg',
|
||||||
|
'image/png'
|
||||||
|
]
|
||||||
|
|
||||||
|
export function isPicture(file) {
|
||||||
|
return fileTypes.includes(file.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function srand(sd) {
|
export function srand(sd) {
|
||||||
seed = sd;
|
seed = sd;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue