图片打印示例
本示例演示如何使用 Taro Bluetooth Print 库打印各种类型的图片,包括网络图片、本地图片、Base64 图片等。
基础图片打印
打印网络图片
typescript
import TaroBluePrint from "taro-bluetooth-print"
async function printNetworkImage() {
const printer = new TaroBluePrint({
debug: true,
paperWidth: 58,
})
try {
// 1. 搜索并连接设备
await printer.bluetooth.startDiscovery({ timeout: 10000 })
const devices = await printer.bluetooth.getDiscoveredDevices()
if (devices.length === 0) {
throw new Error("未找到可用设备")
}
await printer.bluetooth.connect(devices[0].deviceId)
console.log("设备连接成功")
// 2. 打印网络图片
const imageUrl = "https://example.com/logo.png"
console.log("开始打印网络图片:", imageUrl)
await printer.printer.printImage(imageUrl, {
maxWidth: 384,
align: "center",
dithering: true,
})
console.log("网络图片打印成功")
// 3. 走纸和切纸
await printer.printer.feed(2)
await printer.printer.cut()
} catch (error) {
console.error("网络图片打印失败:", error.message)
} finally {
// 4. 断开连接
await printer.bluetooth.disconnect()
}
}
// 执行示例
printNetworkImage()
打印本地图片
typescript
async function printLocalImage() {
const printer = new TaroBluePrint({
debug: true,
paperWidth: 58,
})
try {
// 连接设备(省略连接代码,参考上面的示例)
// 2. 打印本地图片
const localImagePath = "/images/store-logo.png"
console.log("开始打印本地图片:", localImagePath)
await printer.printer.printImage(localImagePath, {
maxWidth: 300,
align: "center",
dithering: false,
})
console.log("本地图片打印成功")
} catch (error) {
console.error("本地图片打印失败:", error.message)
}
}
打印 Base64 图片
typescript
async function printBase64Image() {
const printer = new TaroBluePrint({
debug: true,
paperWidth: 58,
})
try {
// 连接设备(省略连接代码)
// 2. 打印 Base64 图片
const base64Image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
console.log("开始打印 Base64 图片")
await printer.printer.printImage(base64Image, {
maxWidth: 256,
align: "center",
dithering: true,
})
console.log("Base64 图片打印成功")
} catch (error) {
console.error("Base64 图片打印失败:", error.message)
}
}
高级图片处理
图片预处理和优化
typescript
// 图片预处理函数
async function preprocessImage(imagePath: string) {
console.log("开始预处理图片:", imagePath)
try {
// 1. 加载图片
const response = await fetch(imagePath)
const imageBlob = await response.blob()
const imageUrl = URL.createObjectURL(imageBlob)
// 2. 创建图片元素
const img = new Image()
img.src = imageUrl
await new Promise((resolve, reject) => {
img.onload = resolve
img.onerror = reject
})
// 3. 创建 Canvas 进行处理
const canvas = document.createElement("canvas")
const ctx = canvas.getContext("2d")!
// 4. 计算合适的尺寸
const maxWidth = 384
const maxHeight = 300
let { width, height } = img
if (width > maxWidth) {
const ratio = maxWidth / width
width = maxWidth
height = Math.round(height * ratio)
}
if (height > maxHeight) {
const ratio = maxHeight / height
height = maxHeight
width = Math.round(width * ratio)
}
canvas.width = width
canvas.height = height
// 5. 绘制图片
ctx.drawImage(img, 0, 0, width, height)
// 6. 转换为黑白图像
const imageData = ctx.getImageData(0, 0, width, height)
const data = imageData.data
for (let i = 0; i < data.length; i += 4) {
// 计算灰度值
const gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114
// 应用阈值
const threshold = 120
const value = gray > threshold ? 255 : 0
data[i] = value // R
data[i + 1] = value // G
data[i + 2] = value // B
// Alpha 通道保持不变
}
ctx.putImageData(imageData, 0, 0)
// 7. 转换为 Base64
const processedImage = canvas.toDataURL("image/png")
// 8. 清理资源
URL.revokeObjectURL(imageUrl)
console.log("图片预处理完成,新尺寸:", `${width}x${height}`)
return processedImage
} catch (error) {
console.error("图片预处理失败:", error.message)
throw error
}
}
// 使用预处理的图片打印
async function printPreprocessedImage() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 预处理图片
const originalImage = "https://example.com/large-image.jpg"
const processedImage = await preprocessImage(originalImage)
// 打印处理后的图片
await printer.printer.printImage(processedImage, {
maxWidth: 384,
align: "center",
dithering: false, // 已经预处理过,不需要抖动
})
console.log("预处理图片打印成功")
} catch (error) {
console.error("预处理图片打印失败:", error.message)
}
}
批量图片打印
typescript
async function printMultipleImages() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 图片列表
const images = [
{ url: "https://example.com/logo.png", name: "Logo" },
{ url: "https://example.com/qr-code.png", name: "二维码" },
{ url: "https://example.com/promo.png", name: "促销图片" },
]
console.log(`开始批量打印 ${images.length} 张图片`)
for (let i = 0; i < images.length; i++) {
const image = images[i]
console.log(`打印第 ${i + 1} 张图片: ${image.name}`)
// 打印图片标题
await printer.printer.printText(image.name, {
align: "center",
bold: true,
})
await printer.printer.newLine()
// 打印图片
await printer.printer.printImage(image.url, {
maxWidth: 300,
align: "center",
dithering: true,
})
await printer.printer.newLine(2)
// 如果不是最后一张图片,添加分隔线
if (i < images.length - 1) {
await printer.printer.printLine("-", 32)
await printer.printer.newLine()
}
}
// 走纸和切纸
await printer.printer.feed(3)
await printer.printer.cut()
console.log("批量图片打印完成")
} catch (error) {
console.error("批量图片打印失败:", error.message)
}
}
图文混合打印
打印带标题和说明的图片
typescript
async function printImageWithText() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 1. 打印标题
await printer.printer.printText("产品展示", {
align: "center",
bold: true,
fontSize: 2,
})
await printer.printer.newLine()
// 2. 打印图片
const imageUrl = "https://example.com/product-image.jpg"
await printer.printer.printImage(imageUrl, {
maxWidth: 350,
align: "center",
dithering: true,
})
await printer.printer.newLine()
// 3. 打印产品描述
await printer.printer.printText("产品名称:智能蓝牙打印机", {
align: "left",
})
await printer.printer.printText("产品特点:", {
align: "left",
bold: true,
})
const features = [
"• 支持蓝牙连接",
"• 高速打印",
"• 体积小巧",
"• 操作简单",
]
for (const feature of features) {
await printer.printer.printText(feature, {
align: "left",
fontSize: 1,
})
}
await printer.printer.newLine()
// 4. 打印二维码
await printer.printer.printText("扫码了解更多", {
align: "center",
})
await printer.printer.printQRCode("https://example.com/product-info", {
size: 8,
align: "center",
errorCorrection: "M",
})
await printer.printer.newLine()
// 5. 打印价格
await printer.printer.printText("价格:¥299.00", {
align: "center",
bold: true,
fontSize: 2,
})
await printer.printer.feed(3)
await printer.printer.cut()
console.log("图文混合打印完成")
} catch (error) {
console.error("图文混合打印失败:", error.message)
}
}
打印证件照
typescript
async function printIDPhoto() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 1. 打印证件照标题
await printer.printer.printText("证件照", {
align: "center",
bold: true,
fontSize: 2,
})
await printer.printer.newLine()
// 2. 打印照片(证件照通常是正方形)
const photoUrl = "https://example.com/id-photo.jpg"
// 预处理为正方形并优化
const processedPhoto = await preprocessIDPhoto(photoUrl)
await printer.printer.printImage(processedPhoto, {
maxWidth: 256, // 证件照尺寸适中
align: "center",
dithering: true,
})
await printer.printer.newLine()
// 3. 打印个人信息
await printer.printer.printText("姓名:张三", {
align: "center",
})
await printer.printer.printText("性别:男", {
align: "center",
})
await printer.printer.printText("出生日期:1990年01月01日", {
align: "center",
})
await printer.printer.printText("地址:北京市朝阳区", {
align: "center",
})
await printer.printer.newLine()
// 4. 打印编号和日期
await printer.printer.printText("编号:20230001", {
align: "left",
fontSize: 1,
})
await printer.printer.printText("发证日期:2023年09月28日", {
align: "right",
fontSize: 1,
})
await printer.printer.feed(3)
await printer.printer.cut()
console.log("证件照打印完成")
} catch (error) {
console.error("证件照打印失败:", error.message)
}
}
// 证件照预处理函数
async function preprocessIDPhoto(imagePath: string) {
// 类似于前面的 preprocessImage 函数,但针对证件照优化
// 1. 裁剪为正方形
// 2. 调整为标准证件照尺寸
// 3. 优化对比度和亮度
// 4. 转换为黑白图像
// 这里简化实现
return await preprocessImage(imagePath)
}
特殊效果打印
打印带边框的图片
typescript
async function printImageWithBorder() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 1. 打印上边框
await printer.printer.printText("+------------------------------------+", {
align: "center",
})
// 2. 打印图片
const imageUrl = "https://example.com/bordered-image.png"
await printer.printer.printImage(imageUrl, {
maxWidth: 320,
align: "center",
dithering: true,
})
// 3. 打印下边框
await printer.printer.printText("+------------------------------------+", {
align: "center",
})
await printer.printer.feed(2)
await printer.printer.cut()
console.log("带边框图片打印完成")
} catch (error) {
console.error("带边框图片打印失败:", error.message)
}
}
打印水印图片
typescript
async function printWatermarkedImage() {
const printer = new TaroBluePrint({ debug: true })
try {
// 连接设备(省略连接代码)
// 1. 打印主图片
const mainImageUrl = "https://example.com/main-image.jpg"
await printer.printer.printImage(mainImageUrl, {
maxWidth: 350,
align: "center",
dithering: true,
})
await printer.printer.newLine()
// 2. 打印水印文字
await printer.printer.printText("© 2023 示例公司 版权所有", {
align: "center",
fontSize: 1,
})
// 3. 打印水印二维码
await printer.printer.printQRCode("https://example.com/watermark", {
size: 4,
align: "center",
})
await printer.printer.feed(2)
await printer.printer.cut()
console.log("水印图片打印完成")
} catch (error) {
console.error("水印图片打印失败:", error.message)
}
}
错误处理和重试
带重试机制的图片打印
typescript
async function printImageWithRetry(imageUrl: string, maxRetries = 3) {
const printer = new TaroBluePrint({ debug: true })
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`第 ${attempt} 次尝试打印图片`)
// 连接设备
await printer.bluetooth.startDiscovery({ timeout: 5000 })
const devices = await printer.bluetooth.getDiscoveredDevices()
if (devices.length === 0) {
throw new Error("未找到可用设备")
}
await printer.bluetooth.connect(devices[0].deviceId)
// 打印图片
await printer.printer.printImage(imageUrl, {
maxWidth: 384,
align: "center",
dithering: true,
})
await printer.printer.feed(2)
await printer.printer.cut()
console.log("图片打印成功")
return // 成功则返回
} catch (error) {
console.error(`第 ${attempt} 次尝试失败:`, error.message)
if (attempt === maxRetries) {
console.error("所有重试都失败了")
throw error
}
// 等待一段时间后重试
await new Promise((resolve) => setTimeout(resolve, 2000 * attempt))
} finally {
// 确保断开连接
try {
await printer.bluetooth.disconnect()
} catch (error) {
console.error("断开连接失败:", error.message)
}
}
}
}
// 使用示例
printImageWithRetry("https://example.com/retry-image.png", 3)
.then(() => console.log("打印完成"))
.catch((error) => console.error("打印最终失败:", error.message))
性能优化
图片缓存和批量处理
typescript
class ImagePrintCache {
private cache = new Map<string, string>()
private maxCacheSize = 10
async getProcessed(imageUrl: string): Promise<string> {
// 检查缓存
if (this.cache.has(imageUrl)) {
console.log("从缓存获取图片:", imageUrl)
return this.cache.get(imageUrl)!
}
// 处理图片
console.log("处理新图片:", imageUrl)
const processed = await preprocessImage(imageUrl)
// 添加到缓存
if (this.cache.size >= this.maxCacheSize) {
// 删除最旧的缓存项
const firstKey = this.cache.keys().next().value
this.cache.delete(firstKey)
}
this.cache.set(imageUrl, processed)
return processed
}
clear() {
this.cache.clear()
console.log("图片缓存已清空")
}
}
// 使用缓存的批量打印
async function printBatchWithCache(imageUrls: string[]) {
const printer = new TaroBluePrint({ debug: true })
const imageCache = new ImagePrintCache()
try {
// 连接设备(省略连接代码)
console.log(`开始批量打印 ${imageUrls.length} 张图片(使用缓存)`)
for (let i = 0; i < imageUrls.length; i++) {
const imageUrl = imageUrls[i]
console.log(`处理第 ${i + 1} 张图片`)
// 从缓存获取或处理图片
const processedImage = await imageCache.getProcessed(imageUrl)
// 打印图片
await printer.printer.printImage(processedImage, {
maxWidth: 350,
align: "center",
dithering: false, // 已预处理过
})
await printer.printer.newLine()
// 添加分隔
if (i < imageUrls.length - 1) {
await printer.printer.printLine("-", 32)
await printer.printer.newLine()
}
}
await printer.printer.feed(3)
await printer.printer.cut()
console.log("批量打印完成")
} catch (error) {
console.error("批量打印失败:", error.message)
} finally {
imageCache.clear()
}
}
// 使用示例
const imageUrls = [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg",
"https://example.com/image3.jpg",
]
printBatchWithCache(imageUrls)
完整示例
完整的图片打印应用
typescript
import TaroBluePrint from "taro-bluetooth-print"
class ImagePrintApp {
private printer: TaroBluePrint
private isConnected = false
constructor() {
this.printer = new TaroBluePrint({
debug: true,
paperWidth: 58,
})
this.setupEventListeners()
}
private setupEventListeners() {
this.printer.bluetooth.onConnectionStateChange((connected) => {
this.isConnected = connected
console.log(`连接状态变化: ${connected ? "已连接" : "已断开"}`)
})
}
async connectPrinter() {
try {
console.log("开始连接打印机...")
// 搜索设备
await this.printer.bluetooth.startDiscovery({ timeout: 10000 })
const devices = await this.printer.bluetooth.getDiscoveredDevices()
if (devices.length === 0) {
throw new Error("未找到可用设备")
}
// 选择信号最强的设备
const bestDevice = devices.sort(
(a, b) => (b.RSSI || 0) - (a.RSSI || 0)
)[0]
console.log("选择设备:", bestDevice.name)
// 连接设备
const connected = await this.printer.bluetooth.connect(
bestDevice.deviceId
)
if (!connected) {
throw new Error("设备连接失败")
}
console.log("打印机连接成功")
return true
} catch (error) {
console.error("连接打印机失败:", error.message)
return false
}
}
async printImageWithOptions(imageUrl: string, options: any = {}) {
if (!this.isConnected) {
const connected = await this.connectPrinter()
if (!connected) {
throw new Error("无法连接打印机")
}
}
try {
console.log("开始打印图片:", imageUrl)
const defaultOptions = {
maxWidth: 384,
align: "center",
dithering: true,
...options,
}
await this.printer.printer.printImage(imageUrl, defaultOptions)
console.log("图片打印成功")
return true
} catch (error) {
console.error("图片打印失败:", error.message)
return false
}
}
async printImageReport(imageUrl: string, title: string, description: string) {
if (!this.isConnected) {
await this.connectPrinter()
}
try {
// 1. 打印标题
await this.printer.printer.printText(title, {
align: "center",
bold: true,
fontSize: 2,
})
await this.printer.printer.newLine()
// 2. 打印图片
await this.printer.printer.printImage(imageUrl, {
maxWidth: 350,
align: "center",
dithering: true,
})
await this.printer.printer.newLine()
// 3. 打印描述
await this.printer.printer.printText(description, {
align: "left",
})
await this.printer.printer.newLine()
// 4. 打印时间
const now = new Date()
await this.printer.printer.printText(
`打印时间: ${now.toLocaleString()}`,
{
align: "center",
fontSize: 1,
}
)
// 5. 走纸和切纸
await this.printer.printer.feed(3)
await this.printer.printer.cut()
console.log("图片报告打印完成")
} catch (error) {
console.error("图片报告打印失败:", error.message)
}
}
async disconnect() {
if (this.isConnected) {
await this.printer.bluetooth.disconnect()
console.log("打印机已断开连接")
}
}
}
// 使用示例
async function demonstrateImagePrinting() {
const app = new ImagePrintApp()
try {
// 连接打印机
await app.connectPrinter()
// 打印网络图片
await app.printImageWithOptions("https://example.com/logo.png", {
maxWidth: 300,
dithering: false,
})
// 打印图片报告
await app.printImageReport(
"https://example.com/product.jpg",
"产品展示",
"这是一款高质量的蓝牙打印机,具有快速打印、高清晰度等特点。"
)
} catch (error) {
console.error("演示失败:", error.message)
} finally {
// 断开连接
await app.disconnect()
}
}
// 运行演示
demonstrateImagePrinting()
运行示例
安装依赖
bash
npm install taro-bluetooth-print
运行代码
将上述代码保存为 image-print-example.ts
,然后在您的 Taro 项目中运行:
bash
# 如果使用 Vite
npm run dev
# 如果使用 webpack
npm run build
预期输出
打印机会输出:
- 网络图片或本地图片
- 带标题和说明的图文内容
- 证件照格式的内容
- 带边框或水印的图片
关键点说明
- 图片预处理: 在打印前对图片进行尺寸调整和黑白转换,可以提高打印质量和速度
- 抖动算法: 启用抖动可以提高黑白图像的视觉效果
- 尺寸控制: 根据纸张宽度设置合适的图片最大宽度
- 错误处理: 使用 try-catch 和重试机制处理打印失败的情况
- 缓存优化: 对于重复打印的图片,使用缓存可以避免重复处理
- 内存管理: 及时释放不需要的图片资源,避免内存泄漏
扩展功能
查看其他示例了解更多功能: