|
@@ -48,7 +48,7 @@ class PosterUtil
|
|
|
|
|
|
|
|
const MID_LINE_GAP = 6;
|
|
const MID_LINE_GAP = 6;
|
|
|
|
|
|
|
|
- const MID_NAME_SIZE = 38;
|
|
|
|
|
|
|
+ const MID_NAME_SIZE = 42;
|
|
|
|
|
|
|
|
const MID_REMARK_SIZE = 26;
|
|
const MID_REMARK_SIZE = 26;
|
|
|
|
|
|
|
@@ -60,23 +60,14 @@ class PosterUtil
|
|
|
|
|
|
|
|
const QR_PAD_BOTTOM = 32;
|
|
const QR_PAD_BOTTOM = 32;
|
|
|
|
|
|
|
|
- /** 价格下方:灰色圆角条 + 文案(布局参考快团团) */
|
|
|
|
|
|
|
+ /** 价格下方提示文案(与价格左对齐,无背景条) */
|
|
|
const FOOTER_BUY_HINT = '长按识别小程序购买';
|
|
const FOOTER_BUY_HINT = '长按识别小程序购买';
|
|
|
|
|
|
|
|
- const FOOTER_BUY_HINT_SIZE = 26;
|
|
|
|
|
-
|
|
|
|
|
- const FOOTER_BUY_HINT_BAR_H = 48;
|
|
|
|
|
-
|
|
|
|
|
- const FOOTER_BUY_HINT_BAR_RADIUS = 12;
|
|
|
|
|
-
|
|
|
|
|
- const FOOTER_BUY_HINT_BAR_COLOR = 'F2F2F2';
|
|
|
|
|
-
|
|
|
|
|
- /** 灰条左右内边距(条宽 = 文案宽度 + 两侧 padding) */
|
|
|
|
|
- const FOOTER_BUY_HINT_TEXT_PAD_X = 20;
|
|
|
|
|
|
|
+ const FOOTER_BUY_HINT_SIZE = 30;
|
|
|
|
|
|
|
|
const FOOTER_TEXT_GAP = 12;
|
|
const FOOTER_TEXT_GAP = 12;
|
|
|
|
|
|
|
|
- const FOOTER_PRICE_SIZE = 64;
|
|
|
|
|
|
|
+ const FOOTER_PRICE_SIZE = 72;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 与 admin/home/me 一致:门店展示名、Logo 对象路径、itemRemark
|
|
* 与 admin/home/me 一致:门店展示名、Logo 对象路径、itemRemark
|
|
@@ -326,59 +317,28 @@ class PosterUtil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 底部左侧(价格+灰条)与右侧太阳码垂直居中对齐
|
|
|
|
|
|
|
+ * 底部左侧(价格 + 提示文案)与右侧太阳码垂直居中对齐,均左对齐
|
|
|
*
|
|
*
|
|
|
- * @return array{buyHintBarY:int,buyHintBarW:int,buyHintTextY:int,buyHintTextX:int,priceY:int,qrY:int}
|
|
|
|
|
|
|
+ * @return array{buyHintY:int,priceY:int,qrY:int}
|
|
|
*/
|
|
*/
|
|
|
private static function calcFooterLayout()
|
|
private static function calcFooterLayout()
|
|
|
{
|
|
{
|
|
|
$qrCenterFromBottom = self::QR_PAD_BOTTOM + (int)(self::QR_SIZE / 2);
|
|
$qrCenterFromBottom = self::QR_PAD_BOTTOM + (int)(self::QR_SIZE / 2);
|
|
|
- $hintBarH = self::FOOTER_BUY_HINT_BAR_H;
|
|
|
|
|
- $hintBarW = self::calcBuyHintBarWidth(self::FOOTER_BUY_HINT);
|
|
|
|
|
|
|
+ $buyHintH = (int)ceil(self::FOOTER_BUY_HINT_SIZE * 1.2);
|
|
|
$priceH = (int)ceil(self::FOOTER_PRICE_SIZE * 1.3);
|
|
$priceH = (int)ceil(self::FOOTER_PRICE_SIZE * 1.3);
|
|
|
$gap = self::FOOTER_TEXT_GAP;
|
|
$gap = self::FOOTER_TEXT_GAP;
|
|
|
- $blockH = $priceH + $gap + $hintBarH;
|
|
|
|
|
- $buyHintBarY = max(16, $qrCenterFromBottom - (int)($blockH / 2));
|
|
|
|
|
- $priceY = $buyHintBarY + $hintBarH + $gap;
|
|
|
|
|
- $textLineH = (int)ceil(self::FOOTER_BUY_HINT_SIZE * 1.2);
|
|
|
|
|
- $buyHintTextY = $buyHintBarY + (int)(($hintBarH - $textLineH) / 2);
|
|
|
|
|
|
|
+ $blockH = $priceH + $gap + $buyHintH;
|
|
|
|
|
+ $buyHintY = max(16, $qrCenterFromBottom - (int)($blockH / 2));
|
|
|
|
|
+ $priceY = $buyHintY + $buyHintH + $gap;
|
|
|
$qrY = max(16, $qrCenterFromBottom - (int)(self::QR_SIZE / 2));
|
|
$qrY = max(16, $qrCenterFromBottom - (int)(self::QR_SIZE / 2));
|
|
|
|
|
|
|
|
return [
|
|
return [
|
|
|
- 'buyHintBarY' => $buyHintBarY,
|
|
|
|
|
- 'buyHintBarW' => $hintBarW,
|
|
|
|
|
- 'buyHintTextY' => $buyHintTextY,
|
|
|
|
|
- 'buyHintTextX' => self::CANVAS_PAD_X + self::FOOTER_BUY_HINT_TEXT_PAD_X,
|
|
|
|
|
|
|
+ 'buyHintY' => $buyHintY,
|
|
|
'priceY' => $priceY,
|
|
'priceY' => $priceY,
|
|
|
'qrY' => $qrY,
|
|
'qrY' => $qrY,
|
|
|
];
|
|
];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 按文案长度估算灰条宽度,避免条过长导致 OSS 圆角裁切异常 */
|
|
|
|
|
- private static function calcBuyHintBarWidth($text)
|
|
|
|
|
- {
|
|
|
|
|
- $text = self::filterPosterUtf8Text($text);
|
|
|
|
|
- if ($text === '') {
|
|
|
|
|
- $text = self::FOOTER_BUY_HINT;
|
|
|
|
|
- }
|
|
|
|
|
- $charCount = mb_strlen($text, 'UTF-8');
|
|
|
|
|
- $charW = (int)ceil(self::FOOTER_BUY_HINT_SIZE * 1.15);
|
|
|
|
|
- $w = $charCount * $charW + self::FOOTER_BUY_HINT_TEXT_PAD_X * 2;
|
|
|
|
|
-
|
|
|
|
|
- return max(220, min(self::SLOT_W - self::QR_SIZE - self::QR_PAD_RIGHT - 24, $w));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /** OSS 生成灰色小圆角底条 */
|
|
|
|
|
- private static function buildBuyHintBarWatermarkPath($barW)
|
|
|
|
|
- {
|
|
|
|
|
- $w = max(200, (int)$barW);
|
|
|
|
|
- $h = self::FOOTER_BUY_HINT_BAR_H;
|
|
|
|
|
- $r = min(self::FOOTER_BUY_HINT_BAR_RADIUS, (int)floor($h / 2) - 2);
|
|
|
|
|
-
|
|
|
|
|
- return self::BLANK_CANVAS . '?x-oss-process=image/resize,m_fill,w_' . $w . ',h_' . $h
|
|
|
|
|
- . ',color_' . self::FOOTER_BUY_HINT_BAR_COLOR . '/rounded-corners,r_' . $r;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* @return array{imgH:int,totalH:int,scaledH:int,posterW:int,coverY:int,nameY:int,remarkY:int}
|
|
* @return array{imgH:int,totalH:int,scaledH:int,posterW:int,coverY:int,nameY:int,remarkY:int}
|
|
|
*/
|
|
*/
|
|
@@ -563,11 +523,9 @@ class PosterUtil
|
|
|
$url .= '/watermark,image_' . $logoB64 . ',g_se,x_210,y_48';
|
|
$url .= '/watermark,image_' . $logoB64 . ',g_se,x_210,y_48';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- $url .= '/watermark,image_' . stringUtil::ossBase64(self::buildBuyHintBarWatermarkPath($footer['buyHintBarW']))
|
|
|
|
|
- . ',g_sw,x_' . self::CANVAS_PAD_X . ',y_' . $footer['buyHintBarY'];
|
|
|
|
|
$url .= '/watermark,text_' . stringUtil::ossBase64(self::FOOTER_BUY_HINT)
|
|
$url .= '/watermark,text_' . stringUtil::ossBase64(self::FOOTER_BUY_HINT)
|
|
|
- . ',g_sw,x_' . $footer['buyHintTextX'] . ',y_' . $footer['buyHintTextY']
|
|
|
|
|
- . ',color_666666,type_' . self::FONT . ',size_' . self::FOOTER_BUY_HINT_SIZE;
|
|
|
|
|
|
|
+ . ',g_sw,x_' . self::CANVAS_PAD_X . ',y_' . $footer['buyHintY']
|
|
|
|
|
+ . ',color_888888,type_' . self::FONT . ',size_' . self::FOOTER_BUY_HINT_SIZE;
|
|
|
$url .= '/watermark,text_' . stringUtil::ossBase64($priceText)
|
|
$url .= '/watermark,text_' . stringUtil::ossBase64($priceText)
|
|
|
. ',g_sw,x_' . self::CANVAS_PAD_X . ',y_' . $footer['priceY']
|
|
. ',g_sw,x_' . self::CANVAS_PAD_X . ',y_' . $footer['priceY']
|
|
|
. ',color_EE2C2C,type_' . self::FONT . ',size_' . self::FOOTER_PRICE_SIZE;
|
|
. ',color_EE2C2C,type_' . self::FONT . ',size_' . self::FOOTER_PRICE_SIZE;
|