一,需求背景:
某個印刷公司,有一系列的設計檔案模闆。接到客戶訂單時,就在這些設計檔案模闆上,做一些簡單的定制,就能夠滿足客戶的印刷需求。 如在設計檔案模闆上添加客戶的Logo,二維碼,聯系方式等。
1,面臨困境:
a,每天有上千個模闆檔案需要加Logo,文字。印刷公司不得不請幾個設計師來完成這項工作。
b,設計師要不斷的與客戶溝通,如文字顔色,字型,文字大小,二維碼, Logo的位置。
c,設計檔案不能統一歸檔存儲,時間久了容易丢失。
d,工作枯燥泛味(在模闆檔案上更換Logo,添加文字)。
2,解決方案:
a,公司決定開發一個網站,公布設計檔案模闆,讓客戶挑選心儀的檔案模闆。
b,讓客戶自己上傳 Logo,二維碼,添加文字等資訊。
c,系統自動儲存客戶的設計檔案,并與銷售訂單自動關聯。
二,需求轉換為軟體原型
1,圖檔需求:
a,可以在工具欄中,往設計圖檔上添加Logo,二維碼等圖檔資訊
b,對上傳的圖檔要進行移動,放大,縮小,旋轉
c,可以預覽,删除上傳的圖檔
2,文字需求:
a,可以添加與定義文字資訊
b,文字大小,字型,顔色可自定義
c,檔案可以移動,旋轉等功能
d,可以删除文字。
3,軟體原型:
三,技術選型與實作
1,技術選型:
a,印刷行業的圖檔都非常大,小則幾M,大則幾十M,上百M。在網頁上隻能操作縮略圖,然後再生成原圖。
b,要對圖檔,文字進行移動,旋轉,放大縮小,我選擇了Fabric類庫。
c,前端架構主要有3種Vue.js ,React ,Angular 。對我個人來說Vue.js是我最熟悉的架構之一,但是 Vue.js + Fabric 的組合沒有 React + Fabric 成熟。最終我選擇了 React + Fabric的組合。
d,把設計好的圖檔,文字資訊以Json的資料推送到伺服器,通過ImageMagick 技術生成印刷原圖。
2,代碼實作:
前端關鍵代碼:
a,圖檔的移動,放大縮小,旋轉實作:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISM9AnYldnJwAzN9c3Pml2Zu0GbyoVdzJTW2hXbRtmVHRmaG12YwUjMiRUO5NWe5cEZo50VhtWNXNlb1cVY1x2RiBjVzQldwIjYqVTej5WOHJWa1ITW11EWa5mRXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.gif)
img.on('selected',(e) => {
});
img.on('moved',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
}
})
img.on('rotated',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
selectObj.angle = e.target.angle;
var rect = e.target.getBoundingRect();
selectObj.top = rect.top;
selectObj.left = rect.left;
selectObj.width = e.target.width;
selectObj.height = e.target.height;
this.UpdateItemByChild(selectObj);
}
}
})
img.on('scaled',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
if(e.target.scaleX) {
selectObj.scaleX = e.target.scaleX;
}
if(e.target.scaleY) {
selectObj.scaleY = e.target.scaleY;
}
selectObj.width = e.target.width;
selectObj.height = e.target.height;
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
}
});
View Code
b,圖檔在稱動,放大縮小,旋轉時的位置與大小限制:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISM9AnYldnJwAzN9c3Pml2Zu0GbyoVdzJTW2hXbRtmVHRmaG12YwUjMiRUO5NWe5cEZo50VhtWNXNlb1cVY1x2RiBjVzQldwIjYqVTej5WOHJWa1ITW11EWa5mRXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.gif)
img.on('rotating',(e) => {
});
img.on('scaling',(e) => {
var maxWidth = fixedInfo.width;
var maxHeight = fixedInfo.height;
if(e.transform.action === 'scaleX' || e.transform.action === 'scaleY' || e.transform.action === 'scale'){
if(img.width * img.scaleX >= maxWidth){
img.scaleX = maxWidth / img.width;
}
if(img.height * img.scaleY >= maxHeight){
img.scaleY = maxHeight / img.height;
}
}
});
img.on('moving',(e) => {
if(fixedInfo){
if(img.left <= fixedInfo.left || img.top <= fixedInfo.left){
img.setCoords();
img.left = Math.max(img.left, fixedInfo.left);
img.top = Math.max(img.top, fixedInfo.top);
}
let maxLeft = fixedInfo.left + fixedInfo.width - img.width * img.scaleX;
let maxTop = fixedInfo.top + fixedInfo.height - img.height * img.scaleY;
if(img.left >= maxLeft || img.top >= maxTop) {
img.setCoords();
img.left = Math.min(img.left, maxLeft);
img.top = Math.min(img.top, maxTop);
}
}
});
View Code
c,文字的移動,放大縮小,旋轉實作:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISM9AnYldnJwAzN9c3Pml2Zu0GbyoVdzJTW2hXbRtmVHRmaG12YwUjMiRUO5NWe5cEZo50VhtWNXNlb1cVY1x2RiBjVzQldwIjYqVTej5WOHJWa1ITW11EWa5mRXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.gif)
txt.on('moved',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
}
})
txt.on('rotated',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
selectObj.angle = e.target.angle;
selectObj.width = e.target.width;
selectObj.height = e.target.height;
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
}
})
txt.on('scaled',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
if(e.target.scaleX) {
let tempFontSize = Math.ceil(e.target.fontSize * (e.target.scaleX / this.props.templateModel.scaleX));
e.target.fontSize = tempFontSize;
selectObj.fontSize = tempFontSize;
// X軸 Y軸是一樣的縮放
e.target.scaleX = this.props.templateModel.scaleX;
selectObj.scaleX = this.props.templateModel.scaleX;
e.target.scaleY = this.props.templateModel.scaleY;
selectObj.scaleY = this.props.templateModel.scaleY;
selectObj.width = e.target.width;
selectObj.height = e.target.height;
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
this.UpdateItemByChild(selectObj);
}
}
});
View Code
d,特别注意當文字大小改變時,字型大小需要随之變更
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISM9AnYldnJwAzN9c3Pml2Zu0GbyoVdzJTW2hXbRtmVHRmaG12YwUjMiRUO5NWe5cEZo50VhtWNXNlb1cVY1x2RiBjVzQldwIjYqVTej5WOHJWa1ITW11EWa5mRXJGc5kHT20ESjBjUIF2Lc12bj5SYphXa5VWen5WY35iclN3Ztl2Lc9CX6MHc0RHaiojIsJye.gif)
txt.on('scaled',(e) => {
if(e.target) {
let selectObj = this.props.templateModel.rows.filter(d => {return d.uid === e.target.uid})[0];
if(selectObj) {
if(e.target.scaleX) {
let tempFontSize = Math.ceil(e.target.fontSize * (e.target.scaleX / this.props.templateModel.scaleX));
e.target.fontSize = tempFontSize;
selectObj.fontSize = tempFontSize;
// X軸 Y軸是一樣的縮放
e.target.scaleX = this.props.templateModel.scaleX;
selectObj.scaleX = this.props.templateModel.scaleX;
e.target.scaleY = this.props.templateModel.scaleY;
selectObj.scaleY = this.props.templateModel.scaleY;
selectObj.width = e.target.width;
selectObj.height = e.target.height;
selectObj.top = e.target.top;
selectObj.left = e.target.left;
this.UpdateItemByChild(selectObj);
}
this.UpdateItemByChild(selectObj);
}
}
});
View Code
後端關鍵代碼:
a,ImageMagick 把 文字合并在原圖上:
convert -font "H:\Works\Coordinator\Coordinator.MvcWebAPI\ImageMagick\simsun.ttc"
-fill #FE9200 -pointsize 450 -gravity northwest -annotate 28.0971789257395x28.0971789257395+4104.47275822051+437.86943092823 "文字定義"
"H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91.jpg"
"H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91.jpg"
b,ImageMagick 把附加圖檔合并在原圖上:
convert "H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91.jpg" ( -resize 1000x1000!
"https://localhost:44300/01.SourceFiles/diy/20210317/-44a34290d3424b55a04a1f59b03f8e0d.png" -background transparent -rotate 0 )
-gravity northwest -geometry +6798.3525+363.902921615202 -composite
"H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91.jpg"
c,生成原圖與預覽圖:
convert "H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91.jpg"
-resize 1000x
"H:\Works\Coordinator\Coordinator.MvcWebAPI\01.SourceFiles\diy\20210317\140907767-2e86273b978445359c5cdd9be9beef91_s.jpg"
四,軟體預覽
有希望更深層次交流的朋友,請掃描部落格頭像的二維碼
歡迎指正。