Day 15:共通屬性處理優化及 Imagemap 圖片製作
4.0k 字,約 4 分鐘
2025 iThome 鐵人賽:Line Bot × NestJS:30 天開發日記。 原文發表於 iThome,也可以在下方留言。
文章目錄
前言
針對 Day 14 的程式碼架構進行優化。由於 Sender 和 Quick Reply 功能在所有回覆訊息類型中都能使用,我們應該將這些共用屬性抽取為獨立函數進行統一處理。
接下來將詳細說明 ImageMap Message 圖片的製作流程。ImageMap Message 與 Rich Menu 在概念上十分相似,兩者皆需要將圖片劃分為不同的互動區塊,並為每個區塊設定相對應的觸發事件。
ImageMap 處理流程涉及多個工具協作,整體步驟如下:
- Canva 創建 ImageMap 背景圖片:使用 Canva 設計並匯出 ImageMap 所需的背景圖片。
- Bot Designer 產生 JSON 資料:透過 Bot Designer 根據 Canva 創建的背景圖片產生 ImageMap 的 JSON 資料。由於 ImageMap 的參數設定較為複雜,建議使用 Bot Designer 來自動產生基礎結構。
- 處理 baseUrl 的限制問題:Bot Designer 產生的 JSON 中包含 baseUrl 參數,但直接使用 Cloudinary 的網址並不符合 LINE ImageMap 的規範。
- 不能包含副檔名
- 必須支援動態路徑存取五種不同解析度(240、300、460、700、1040)
- CloudFlare Worker 作為代理層:為了解決上述限制,我們需要建立 CloudFlare Worker 作為代理層,處理副檔名移除和動態解析度路由的問題。
- 手動調整 JSON 的 baseUrl:將 Bot Designer 產生的 JSON 中的 baseUrl 替換成 CloudFlare Worker 的端點網址。
- 完成部署:修改後的 JSON 即可直接應用於後端伺服器,成功發送 LINE ImageMap 訊息。
今天主要會說明 1 ~ 3 項。
本日程式碼的範例連結
Sender 和 Quick Reply 優化
- Sender:自定義頭像及名稱
- Quick Reply:快速回覆按鈕
Step 1:共通型別定義
定義可選屬性,可應用於各種訊息型別
line-message/message-common.ts
import { QuickReplyItem, Sender } from '@line/bot-sdk';
export type MessageCommon = {
sender?: Sender;
quickReplyItems?: Omit<QuickReplyItem, 'type'>[];
};
Step 2:將回覆請求與共通型別結合為聯合型別
目前定義的所有訊息型別都可以加上共通型別
line-message/types/template-button-message.ts
import { Action } from '@line/bot-sdk';
import { MessageCommon } from './message-common';
type HttpsURL = `https://${string}`;
export type TemplateButtonMessageReq = MessageCommon & {
altText: string;
text: string;
actions: Action[];
title?: string;
thumbnailImageUrl?: HttpsURL;
};
Step 3:定義私有方法處理共通屬性
建立私有處理方法,讓所有訊息請求都能共用此功能
line-message/line-message.service.ts
private buildCommonMessageProps(
sender: Sender,
quickReplyItems: Omit<QuickReplyItem, 'type'>[],
): CommonMessageProps {
return {
...(sender && { sender }),
...(quickReplyItems && {
quickReply: {
items: quickReplyItems.map((quickReplyItem) => ({
type: 'action' as const,
...quickReplyItem,
})),
},
}),
};
}
Step 4:在處理方法中使用私有方法處理共同屬性
以 Template Button Message 的
createTemplateButtonMessage方法為例
line-message/line-message.service.ts
createTemplateButtonMessage(
templateButtonMessageReq: TemplateButtonMessageReq,
): TemplateMessage {
const {
altText,
text,
actions,
thumbnailImageUrl,
title,
sender,
quickReplyItems,
} = templateButtonMessageReq;
const templateButtonMessage: TemplateMessage = {
type: MessageType.Template,
altText,
template: {
type: MessageType.TemplateButton,
text,
actions,
title,
...(thumbnailImageUrl && { thumbnailImageUrl }),
},
...this.buildCommonMessageProps(sender, quickReplyItems), // 加入共同處理的部分
};
return templateButtonMessage;
}
透過這種方式,後續新增其他回覆訊息的處理函數時,就能快速整合共同屬性功能,提升開發效率。
ImageMap Message
ImageMap Message 與一般圖片訊息有兩個主要差異。首先,顯示區域比一般 Image Message 更大,如同海報般的呈現效果;其次,可在圖片上設定互動區域,讓使用者點擊特定區塊觸發對應事件。
ImageMap 有兩個嚴格的規範必須遵守才能成功發送:
- 圖像連結限制:URL 不能包含任何副檔名(如 .jpeg、.png 等)
- 多尺寸需求:圖像必須提供五種不同寬度的版本,分別為
240px、300px、460px、700px、1040px。建議以1040px作為設計基底,再依比例縮放至其他尺寸。LINE 平台會根據使用者裝置解析度自動選擇最適合的圖片尺寸,並透過baseUrl/{image width}格式來動態載入不同解析度的圖片。
D+ AF 官方帳號 ImageMap 訊息
王品集團官方帳號 ImageMap 訊息
使用 Canva 製作 ImageMap 圖片
製作 ImageMap 圖片時,建議搭配 Canva 的尺規功能,能更準確掌握圖片在各區塊內的呈現效果。設定自訂尺寸為 1040 x 1040 像素,以最大解析度作為設計基準。
完成尺規設定後,使用形狀工具將畫布分割成四個矩形區塊,再將準備好的圖片素材匯入各區塊(範例使用 Unsplash 免費圖片)。
至此完成了 ImageMap 圖片的製作!接下來需要將圖片上傳至 Cloudinary 生成對應的 HTTPS URL。
完成圖片部署後,即可使用 LINE Bot Designer 進行互動區域設定,快速產生所需的 JSON 配置。
透過 Bot Designer 快速生成 ImageMap JSON 配置
ImageMap 最多支援 20 個區塊限制
將 Canva 製作的圖片以 PNG 格式下載並匯入 Bot Designer。使用滑鼠拖曳框選功能圈選對應區域,被選取的區塊將會亮起以便確認位置。根據圖片設計內容決定切割區塊的數量,以目前的規劃為例共分為四個區塊,接著為每個區域設定相對應的觸發事件(Action)。
區塊可以觸發的事件有三種:
- uri:點擊後打開對應連結。
- message:點擊後發送對應訊息。
- clipboard:點擊後將對應訊息複製到用戶剪貼簿上。
這邊注意到一件事情,即使很多地方都可以設置
action,但是能設置的種類是不同的
這邊我們都先設置 message action,點擊到對應的圖片發送訊息!
Cloudinary 產生五種不同尺寸的照片
這裡我們善用 Cloudinary 的圖片轉換功能,能快速產生五種不同解析度的圖片版本。
Cloudinary URL 結構:
https://res.cloudinary.com/<cloud_name>/image/upload/<transformation>/<public_id>
因此我們只需調整網址格式,在 transformation 參數中加入寬度設定:
w_240,f_auto,q_auto:設定寬度為 240px,高度及品質自動最佳化
調整後的網址範例:
https://res.cloudinary.com/dseg0uwc9/image/upload/w_240,f_auto,q_auto/v1754466769/2025%20IT%20%E9%90%B5%E4%BA%BA%E8%B3%BD/ImageMap_02_escz9a.png
透過這種方式,我們可以快速產生五種不同解析度的圖片版本。
然而,雖然 Cloudinary 能產生五種尺寸的圖片,但仔細觀察 URL 會發現仍違反 ImageMap 規範。不僅網址存在 .png 副檔名,也無法直接透過路由參數方式替換不同解析度,例如:透過 https://example.com/bot/images/rm001/240 來讀取 240px 的圖片。
這部分我們將會在明天透過 CloudFlare Worker 的方式進行圖片代理,解決這個問題。
本日結語
今天我們主要聚焦於優化 Sender 和 Quick Reply 的管理方式,讓 LINE Bot 處理訊息傳遞時能夠減少參數複雜度,讓開發者能以更直觀的方式使用這些服務。
另一方面則專注於 ImageMap 的圖片製作流程。由於 ImageMap 有較為嚴格的技術限制,製作過程需要搭配多種工具。這邊盡可能採用服務免費方案,讓大家在學習體驗的同時,也能實際製作出理想的成果。
雖然本篇展示的是四格 ImageMap 設計,但在實務應用中,將 ImageMap 設置為單一區塊來呈現海報般的視覺效果也很常見,這種應用方式我們會在後續內容中進行展示。
留言
留言使用 GitHub 帳號登入(Giscus),留言會存在 GitHub Discussions。