feat(PosterBuilder): 添加海报图片cover/contain适配模式支持
补充Image类型的mode属性定义,重构图片绘制的尺寸计算逻辑以适配两种缩放模式;同时更新签到详情页的活动logo配置,使用contain模式并调整其位置与尺寸参数
Showing
3 changed files
with
36 additions
and
18 deletions
| ... | @@ -48,6 +48,7 @@ export interface Image { | ... | @@ -48,6 +48,7 @@ export interface Image { |
| 48 | url: string; | 48 | url: string; |
| 49 | width: number; | 49 | width: number; |
| 50 | height: number; | 50 | height: number; |
| 51 | + mode?: 'cover' | 'contain'; | ||
| 51 | borderRadius?: number; | 52 | borderRadius?: number; |
| 52 | borderRadiusGroup?: number[]; | 53 | borderRadiusGroup?: number[]; |
| 53 | borderWidth?: number; | 54 | borderWidth?: number; | ... | ... |
| ... | @@ -251,7 +251,7 @@ export const batchGetImageInfo = (images) => { | ... | @@ -251,7 +251,7 @@ export const batchGetImageInfo = (images) => { |
| 251 | */ | 251 | */ |
| 252 | export const getImageInfo = (item, index) => | 252 | export const getImageInfo = (item, index) => |
| 253 | new Promise((resolve, reject) => { | 253 | new Promise((resolve, reject) => { |
| 254 | - const { x, y, width, height, url, zIndex } = item; | 254 | + const { x, y, width, height, url, zIndex, mode = 'cover' } = item; |
| 255 | 255 | ||
| 256 | // 预先计算一些固定值,避免重复计算 | 256 | // 预先计算一些固定值,避免重复计算 |
| 257 | const borderRadius = item.borderRadius || 0; | 257 | const borderRadius = item.borderRadius || 0; |
| ... | @@ -265,21 +265,36 @@ export const getImageInfo = (item, index) => | ... | @@ -265,21 +265,36 @@ export const getImageInfo = (item, index) => |
| 265 | Taro.getImageInfo({ src: imgPath }) | 265 | Taro.getImageInfo({ src: imgPath }) |
| 266 | .then((imgInfo) => { | 266 | .then((imgInfo) => { |
| 267 | // 获取图片信息 | 267 | // 获取图片信息 |
| 268 | - // 根据画布的宽高计算出图片绘制的大小,这里会保证图片绘制不变形, 即宽高比不变,截取再拉伸 | 268 | + // 根据画布的宽高计算出图片绘制的大小 |
| 269 | const imgWidth = toRpx(imgInfo.width); // 图片真实宽度 单位 px | 269 | const imgWidth = toRpx(imgInfo.width); // 图片真实宽度 单位 px |
| 270 | const imgHeight = toRpx(imgInfo.height); // 图片真实高度 单位 px | 270 | const imgHeight = toRpx(imgInfo.height); // 图片真实高度 单位 px |
| 271 | 271 | ||
| 272 | - // 优化计算逻辑,减少重复计算 | ||
| 273 | const aspectRatio = imgWidth / imgHeight; | 272 | const aspectRatio = imgWidth / imgHeight; |
| 274 | const targetRatio = width / height; | 273 | const targetRatio = width / height; |
| 275 | - | 274 | + |
| 276 | - let sx, sy; // 截图的起点坐标 | 275 | + let sx = 0; |
| 277 | - if (aspectRatio <= targetRatio) { | 276 | + let sy = 0; |
| 278 | - sx = 0; | 277 | + let sw = imgWidth; |
| 278 | + let sh = imgHeight; | ||
| 279 | + let drawX = x; | ||
| 280 | + let drawY = y; | ||
| 281 | + let drawW = width; | ||
| 282 | + let drawH = height; | ||
| 283 | + | ||
| 284 | + if (mode === 'contain') { | ||
| 285 | + if (aspectRatio > targetRatio) { | ||
| 286 | + drawH = width / aspectRatio; | ||
| 287 | + drawY = y + (height - drawH) / 2; | ||
| 288 | + } else { | ||
| 289 | + drawW = height * aspectRatio; | ||
| 290 | + drawX = x + (width - drawW) / 2; | ||
| 291 | + } | ||
| 292 | + } else if (aspectRatio <= targetRatio) { | ||
| 279 | sy = (imgHeight - (imgWidth / width) * height) / 2; | 293 | sy = (imgHeight - (imgWidth / width) * height) / 2; |
| 294 | + sh = imgHeight - sy * 2; | ||
| 280 | } else { | 295 | } else { |
| 281 | - sy = 0; | ||
| 282 | sx = (imgWidth - (imgHeight / height) * width) / 2; | 296 | sx = (imgWidth - (imgHeight / height) * width) / 2; |
| 297 | + sw = imgWidth - sx * 2; | ||
| 283 | } | 298 | } |
| 284 | 299 | ||
| 285 | // 给 canvas 画图准备参数,详见 ./draw.ts-drawImage | 300 | // 给 canvas 画图准备参数,详见 ./draw.ts-drawImage |
| ... | @@ -291,14 +306,15 @@ export const getImageInfo = (item, index) => | ... | @@ -291,14 +306,15 @@ export const getImageInfo = (item, index) => |
| 291 | borderRadiusGroup, | 306 | borderRadiusGroup, |
| 292 | zIndex: itemZIndex, | 307 | zIndex: itemZIndex, |
| 293 | imgPath: imgPath, // 使用下载后的临时文件路径 | 308 | imgPath: imgPath, // 使用下载后的临时文件路径 |
| 309 | + mode, | ||
| 294 | sx, | 310 | sx, |
| 295 | sy, | 311 | sy, |
| 296 | - sw: imgWidth - sx * 2, | 312 | + sw, |
| 297 | - sh: imgHeight - sy * 2, | 313 | + sh, |
| 298 | - x, | 314 | + x: drawX, |
| 299 | - y, | 315 | + y: drawY, |
| 300 | - w: width, | 316 | + w: drawW, |
| 301 | - h: height | 317 | + h: drawH |
| 302 | }; | 318 | }; |
| 303 | resolve(result); | 319 | resolve(result); |
| 304 | }) | 320 | }) | ... | ... |
| ... | @@ -448,11 +448,12 @@ const posterConfig = computed(() => { | ... | @@ -448,11 +448,12 @@ const posterConfig = computed(() => { |
| 448 | }, | 448 | }, |
| 449 | // 活动logo | 449 | // 活动logo |
| 450 | { | 450 | { |
| 451 | - x: 360, // 按比例调整 (450 * 0.8 = 360) | 451 | + x: 328, |
| 452 | - y: 32, // 按比例调整 (40 * 0.8 = 32) | 452 | + y: 24, |
| 453 | - width: 200, // 按比例调整 (250 * 0.8 = 200) | 453 | + width: 240, |
| 454 | - height: 64, // 按比例调整 (80 * 0.8 = 64) | 454 | + height: 88, |
| 455 | url: currentMockData.value.activity.logo, | 455 | url: currentMockData.value.activity.logo, |
| 456 | + mode: 'contain', | ||
| 456 | zIndex: 2, | 457 | zIndex: 2, |
| 457 | }, | 458 | }, |
| 458 | // 关卡徽章 | 459 | // 关卡徽章 | ... | ... |
-
Please register or login to post a comment