目前專案的後端 API 已經能夠根據使用者的輸入產生客製化的 QR Code。不過,QR Code 不只能展示資料,它的外觀也可以根據使用者的喜好進行調整。所以今天,我們要來實作一個新的功能,可以讓使用者自行選擇 QR Code 的前景和背景色。
為了實現這個功能,我們需要先擴充 Info
結構,這樣就可以接收顏色的資訊:
#[derive(serde::Deserialize)]
struct Info {
url: String,
foreground: Option<String>,
background: Option<String>,
}
其中的 foreground
和 background
參數是選填的,使用者如果不輸入,我們可以使用預設的顏色。
由於 qrcode
這個套件中,對於 image 似乎沒有修改顏色的方法,但是有針對修改顏色這部分,用在了 svg 上,所以我們先從 qrcode
中取出 svg。
然後預想這個新的 API 會使用 POST 來處理,所以也要從 actix_web
中取出 post
。
use actix_web::{get, post, web, App, HttpResponse, HttpServer};
use image::{DynamicImage, Luma};
use qrcode::render::svg;
use qrcode::QrCode;
接著來到今天的主軸,新增一個使用 post
的函式:
#[post("/generate_qr_svg")]
async fn generate_svg(data: web::Json<Info>) -> HttpResponse {
let fg_color_str = match &data.foreground {
Some(color) => color,
None => "#000000",
};
let bg_color_str = match &data.background {
Some(color) => color,
None => "#FFFFFF",
};
let code = match QrCode::new(data.url.as_bytes()) {
Ok(c) => c,
Err(_) => return HttpResponse::BadRequest().body("你輸入的字串無法處理"),
};
let image = code
.render()
.min_dimensions(200, 200)
.dark_color(svg::Color(fg_color_str))
.light_color(svg::Color(bg_color_str))
.build();
HttpResponse::Ok().content_type("image/svg+xml").body(image)
}
然後在 main()
新增一個 service
:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(index).service(generate_svg))
.bind("127.0.0.1:8080")?
.run()
.await
}
然後接下來由於要使用 POST 來呼叫 API,所以我們使用 Postman 來測試。
URL 傳入 http://127.0.0.1:8080/generate_qr_svg
,然後 Body 傳入 JSON 格式,例如:
{
"url": "https://buckychu.im",
"foreground": "#0375a6",
"background": "#ffff80"
}
就可以得到以下的結果:
前面提到顏色的部分是選填,所以我們也測試一下如果沒加上顏色會怎麼樣:
看起來好像沒問題,不過如果傳入的 JSON 格式是這樣的話:
{
"url": "https://buckychu.im",
"foreground": "",
"background": ""
}
所得到的結果會是一團黑的圖片:
雖然說我們可以在前端幫忙處理,不過這樣總是不夠完整。
針對這個問題,我們可以使用正則表達式來驗證輸入的顏色字符串。
首先在 Terminal 安裝 regex 這個套件:
cargo add regex
並且引入 regex:
use regex::Regex;
然後新增一個函式來幫助我們驗證:
fn is_valid_color(color: &str) -> bool {
let re = Regex::new(r"^#[0-9a-fA-F]{6}$").unwrap();
re.is_match(color)
}
接下來來驗證一下輸入的顏色是否符合:
#[post("/generate_qr_svg")]
async fn generate_svg(data: web::Json<Info>) -> HttpResponse {
let fg_color_str = match &data.foreground {
Some(color) if is_valid_color(color) => color,
_ => "#000000",
};
let bg_color_str = match &data.background {
Some(color) if is_valid_color(color) => color,
_ => "#FFFFFF",
};
// 以下省略
重新啟動專案後,再測試一下應該就沒問題了。
今天增加了顏色自訂功能,讓使用者可以根據自己的喜好進行調整。明天我們將繼續優化這個專案,加入更多實用功能,敬請期待!