採用React + Fabric + ImageMagick 實現大圖片DIY定製

Sam Xiao發表於2021-03-17

一,需求背景:

某個印刷公司,有一系列的設計檔案模板。接到客戶訂單時,就在這些設計檔案模板上,做一些簡單的定製,就能夠滿足客戶的印刷需求。 如在設計檔案模板上新增客戶的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,圖片的移動,放大縮小,旋轉實現:

採用React + Fabric  +  ImageMagick 實現大圖片DIY定製
                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,圖片在稱動,放大縮小,旋轉時的位置與大小約束:

採用React + Fabric  +  ImageMagick 實現大圖片DIY定製
                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,文字的移動,放大縮小,旋轉實現:

採用React + Fabric  +  ImageMagick 實現大圖片DIY定製
                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,特別注意當文字大小改變時,字型大小需要隨之變更

採用React + Fabric  +  ImageMagick 實現大圖片DIY定製
                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" 

四,軟體預覽

有希望更深層次交流的朋友,請掃描部落格頭像的二維碼

 

 歡迎指正。

相關文章