canvas
生成海報 - 解決屏幕圖片失真,解決沒法使用外網圖片源代碼在最下方javascript
canvas(畫布) 元素用於在網頁上繪製圖形。畫布是一個矩形區域,您能夠控制其每一像素。canvas 擁有多種繪製路徑、矩形、圓形、字符以及添加圖像的方法。css
須要注意的是,目前的canvas能夠簡單分爲兩種。一種是傳統網頁中的canvas,一種是小程序中的canvas。二者的功能是徹底同樣的。只是標籤的樣式,和 api
略有區別而已。目前咱們主要講解小程序中的canvas。html
咱們來畫一條直線
在canvas中,把畫直線的步驟分解爲如下幾步:
默認的寬高 爲 300px * 150 px
不一樣於普通的標籤,必需要提供一個屬性
canvas-id
,用於在 js中獲取該對象(不是dom對象!!!)
<canvas canvas-id="firstCanvas"></canvas>
複製代碼
經過 canvas-id 來獲取
該實例 不是dom元素,能夠理解爲另外一種對象如 Math Date String等便可
index.js
Page({
onLoad() {
// 1 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
console.log(context);
}
})
複製代碼
在canvas中,存在一個座標系 以下圖:
咱們在canvas中所講的座標都是相對於canvas內部座標而言
定個起點
// 定起點
context.moveTo(10, 10);
複製代碼
// 定終點
context.lineTo(300,150);
複製代碼
// 連線
context.stroke();
複製代碼
// 上色
context.draw();
複製代碼
index.wxml
<!-- 1 寫標籤 -->
<canvas canvas-id="firstCanvas"></canvas>
複製代碼
index.js
Page({
onLoad() {
// 2 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
// 3 定起點
context.moveTo(10, 10);
// 4 定終點
context.lineTo(300,150);
// 5 連線
context.stroke();
// 6 上色
context.draw();
}
})
複製代碼
canvas中還封裝了畫規則圖形的方法,如:
CanvasContext.strokeRect(number x, number y, number width, number height)
CanvasContext.strokeRect(畫在畫布的X,畫在畫布的Y,畫多寬,畫多高)
// 1 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
// 2 調用canvas內置的畫「矩形」的方法
context.strokeRect(10, 10, 100, 100);
// 3 上色
context.draw();
複製代碼
CanvasContext.arc(number x, number y, number r, number sAngle, number eAngle, boolean counterclockwise)
CanvasContext.arc(圓心的橫座標X,圓心的縱座標Y, 半徑的長度, 開始的弧度, 結束的弧度, ?是否反向來畫)
drawArc() {
// 1 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
// context.arc(圓心的橫座標X,圓心的縱座標Y, 半徑的長度, 開始的弧度, 結束的弧度);
// 2 調用內置的畫 「圓弧」 的方法
context.arc(100, 100, 100, this.angleToArc(0), this.angleToArc(90));
// 3 開始描邊
context.stroke();
// 4 上色
context.draw();
},
/** * 將角度轉爲弧度 * @param {number} angle 角度 */
angleToArc(angle) {
return angle * Math.PI / 180;
}
複製代碼
CanvasContext.fillRect(number x, number y, number width, number height)
// 1 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
// 2 調用canvas內置的 畫填充 「矩形」的方法
context.fillRect(10, 10, 100, 100);
// 3 上色
context.draw();
複製代碼
CanvasContext.strokeText(string text, number x, number y, number maxWidth)
CanvasContext.strokeText(要繪製的文本, 文本起始點的 x 軸座標, number y, 須要繪製的最大寬度,可選)
// 1 獲取畫布上下文對象
const context = wx.createCanvasContext("firstCanvas");
// 2 畫 「文字」
context.strokeText("hello world", 100, 100);
// 3 上色
context.draw();
複製代碼
通過以上的演示咱們也發現,線條的顏色一直是黑色,這確定是沒法知足咱們騷跳的心的。如今來學習一下關於設置canvas線條樣式相關API。
**特別要注意 **,setStrokeStyle
是個函數,1.9.90版本後中止維護,使用如下的方式來修改。
CanvasContext.setStrokeStyle("red")
CanvasContext.strokeStyle="red";
正解const context = wx.createCanvasContext("firstCanvas");
context.moveTo(10, 10);
context.lineTo(300, 150);
// 5 修改顏色 須要在stroke以前修改
context.strokeStyle = "red";
context.stroke();
context.draw();
複製代碼
**特別要注意 **,setLineWidth
是個函數,1.9.90版本後中止維護,使用如下的方式來修改。
CanvasContext.setLineWidth(20)
CanvasContext.lineWidth=20;
正解const context = wx.createCanvasContext("firstCanvas");
context.moveTo(10, 10);
context.lineTo(300, 150);
// 設置線條寬度
context.lineWidth = 20;
context.stroke();
context.draw();
複製代碼
**特別要注意 **,setFillStyle
是個函數,1.9.90版本後中止維護,使用如下的方式來修改。
CanvasContext.setFillStyle("red")
CanvasContext.fillStyle="red";
正解const context = wx.createCanvasContext("firstCanvas");
// 設置填充顏色
context.fillStyle = "red";
context.fillRect(10, 10, 100, 100);
context.draw();
複製代碼
**特別要注意 **,setFontSize
是個函數,1.9.90版本後中止維護,使用如下的方式來修改。
CanvasContext.setFontSize("20")
CanvasContext.font="sans-serif";
正解font
當前字體樣式的屬性。符合 CSS font 語法 的 DOMString 字符串,至少須要提供字體大小和字體族名。默認值爲 10px sans-serif。const context = wx.createCanvasContext("firstCanvas");
// 必需要同時提供 字號 和 字體
context.font="10px sans-serif";
context.strokeText("10px", 10, 10);
// 必需要同時提供 字號 和 字體
context.font="50px sans-serif";
context.strokeText("50px", 50, 100);
// 必需要同時提供 字號 和 字體
context.font="80px sans-serif";
context.strokeText("80px", 80, 180);
context.draw();
複製代碼
在本環節主要講解稍微複雜一點的功能。要實現如下功能
可是須要先作一點技術鋪墊
主要用到的api有:
如下api是實現以上案例所必須的
獲取屏幕大小、設備像素比等
wx.getSystemInfo({
success (res) {
console.log(res.model)
console.log(res.pixelRatio)
console.log(res.windowWidth)
console.log(res.windowHeight)
console.log(res.language)
console.log(res.version)
console.log(res.platform)
}
})
複製代碼
從本地相冊選擇圖片或使用相機拍照
wx.chooseImage({
count: 1,// 最多能夠選擇的圖片張數
sizeType: ['original', 'compressed'],// 所選的圖片的尺寸
sourceType: ['album', 'camera'],// 選擇圖片的來源
success (res) {
// tempFilePath能夠做爲img標籤的src屬性顯示圖片
const tempFilePaths = res.tempFilePaths
}
})
複製代碼
wx.getSystemInfo({
success (res) {
console.log(res.model)
console.log(res.pixelRatio)
console.log(res.windowWidth)
console.log(res.windowHeight)
console.log(res.language)
console.log(res.version)
console.log(res.platform)
}
})
複製代碼
獲取圖片信息。網絡圖片需先配置download域名才能生效。
canvas提供了將圖片畫到畫布上的功能,可是要求所提供的圖片必須是外網下的圖片
所以能夠藉助該方法將網絡圖片變成本地圖片,同時返回該圖片的信息
wx.getImageInfo({
src: 'cloud://c-73e071.632d-c-73e071/92637.jpg',
success (res) {
console.log(res.width)
console.log(res.height)
}
})
複製代碼
不能使用本地圖片,要使用外網圖片的 必需要先 使用
wx.getImageInfo
下載到本地
有三個版本的寫法:
context.drawImage('xxxx.jpg', 0, 0,100, 100);
複製代碼
在 draw() 回調裏調用該方法才能保證圖片導出成功
wx.canvasToTempFilePath({
x: 100,
y: 200,
width: 50,
height: 50,
destWidth: 100,
destHeight: 100,
canvasId: 'myCanvas',
success(res) {
console.log(res.tempFilePath)
}
})
複製代碼
保存圖片到系統相冊
wx.saveImageToPhotosAlbum({
success(res) { }
})
複製代碼
其實要實現同樣案例,最麻煩的不是這些API的調用,而是如何根據不一樣的圖片,合成比例合適的 不模糊的圖片;
由於在canvas中,只支持 px
單位,那麼在使用javascript
來描繪圖片時,就不存在 rpx
、vw
、%
這些相對單位了。只能依靠手動來計算。如,在 canvas中,畫出一個大小爲 屏幕寬的一半 屏幕高的一半的矩形?
問題的緣由仍是由於 手機的屏幕 都是高清屏,具體的緣由能夠參照 連接
如咱們想要生成圖片大小爲 100px * 100px,那麼就須要將 canvas的大小設置爲 width = 圖片的寬度 * 設備像素比
height = 圖片的高度 * 設備像素比
index
首頁result
合成圖片的頁面<!-- 用來顯示 被選擇的圖片的 -->
<image mode="widthFix" src="{{src}}"></image>
<!-- 選擇相冊圖片 -->
<button bindtap="handleTap">選擇圖片</button>
<!-- 跳轉到 結果頁面 -->
<button bindtap="handleCreateFlag">生成小紅旗</button>
複製代碼
主要實現3個功能
Page({
data: {
src: ""
},
// 選擇圖片
handleTap() {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (result) => {
this.setData({
src: result.tempFilePaths[0]
})
// 保存圖片路徑
wx.setStorageSync('src', this.data.src);
}
});
},
// 生成紅旗
handleCreateFlag() {
// 跳轉到結果頁面
wx.navigateTo({
url: '/pages/result/index'
});
}
})
複製代碼
3個標籤
<!-- canvas 標籤-->
<canvas class="cas" style="width:{{canvasWidth}};height:{{canvasHeight}};" canvas-id="firstCanvas"></canvas>
<!-- 用來顯示 合成成功的圖片 -->
<image class="res_image" mode="widthFix" src="{{resSrc}}"></image>
<!-- 點擊下載圖片 -->
<button bindtap="handleSave">下載圖片</button>
複製代碼
兩個樣式
page {
overflow-x: hidden;
overflow-y: auto;
width: 100vw;
height: 100vh;
}
.cas {
position: absolute;
top: 1000vw;
left: 1000vh;
z-index: -1;
opacity: 0;
}
.res_image {
width: 100%;
display: block;
}
複製代碼
易錯點:
import regeneratorRuntime from '../../lib/runtime/runtime';
import { getImageInfo, canvasToTempFilePath, saveImageToPhotosAlbum } from "../../wxAsync/index.js";
Page({
data: {
// 默認的canvas的寬度
canvasWidth: 1,
// 默認的canvas高度
canvasHeight: 1,
// 最終生成的圖片路徑
resSrc: ""
},
// 全局變量
saveImgSrc: "",
async onLoad() {
// 紅旗圖片
const flagSrc = "https://632d-c-73e071-1252056196.tcb.qcloud.la/3434.jpg?sign=a4f1c2106d1e61551829c2f99820c0ba&t=1569678566";
// const baseSrc = "https://632d-c-73e071-1252056196.tcb.qcloud.la/92637.jpg?sign=8952d1eaa69a35510418fe25dc25d6c5&t=1569678606";
// 上個頁面選擇的圖片路徑 柯南圖片
const baseSrc = wx.getStorageSync("src");
// 設備像素比
const { pixelRatio } = wx.getSystemInfoSync();
// 獲取 畫布實例
const context = wx.createCanvasContext('firstCanvas');
console.log(context);
// 下載到本地的 柯南圖片
const baseImg = await getImageInfo(baseSrc);
// 下載到本地的 紅旗圖片
const flagImg = await getImageInfo(flagSrc);
// 將canvas的寬度設置中 圖片的寬度
const canvasWidth = baseImg.width + "px";
// 將canvas的寬度設置中 圖片的高度
const canvasHeight = baseImg.height + "px";
// setData 函數用於將數據從邏輯層發送到視圖層(異步),同時改變對應的 this.data 的值(同步)。
// 所以須要將 描繪 圖片的步驟寫在回調中,不然 真機調試有bug!
this.setData({ canvasWidth, canvasHeight }, () => {
// 若是個別機型出現圖片失敗錯誤,能夠加上定時器。
setTimeout(() => {
// 先將柯南 描繪到畫布上
context.drawImage(baseImg.path, 0, 0, baseImg.width, baseImg.height);
// 把紅旗 描繪到畫布上
context.drawImage(flagImg.path, baseImg.width - (pixelRatio * 50), baseImg.height - (pixelRatio * 50), (pixelRatio * 50), (pixelRatio * 50));
context.draw(true, async () => {
// 將 畫布生成 成圖片
const res1 = await canvasToTempFilePath({
canvasId: "firstCanvas"
});
// 讓圖片顯示 合成後的效果
this.setData({ resSrc: res1.tempFilePath })
// 保存起來,當點擊保存圖片時調用
this.saveImgSrc = res1.tempFilePath;
});
}, 100);
});
},
// 點擊保存圖片
handleSave() {
saveImageToPhotosAlbum(this.saveImgSrc);
}
})
複製代碼
https://github.com/itcastWsy/AppletPoster.git
複製代碼