Просмотр исходного кода

Merge branch 'hsposter' into dev

shish 2 месяцев назад
Родитель
Сommit
4aafe03e46
1 измененных файлов с 67 добавлено и 17 удалено
  1. 67 17
      common/components/PosterUtil.php

+ 67 - 17
common/components/PosterUtil.php

@@ -16,18 +16,28 @@ class PosterUtil
 
     const SLOT_W = 700;
 
+    /** 底部价格/标题/太阳码固定区 */
     const FOOTER_H = 360;
 
-    const IMG_H_MIN = 480;
+    /** 主图区温和下限,避免扁图海报过矮 */
+    const IMG_H_MIN = 240;
 
     const IMG_H_MAX = 880;
 
-    const TOTAL_H_MIN = 840;
-
     const TOTAL_H_MAX = 1600;
 
     const CANVAS_COLOR = 'FFFFFF';
 
+    const QR_SIZE = 220;
+
+    const QR_PAD_RIGHT = 36;
+
+    const QR_PAD_BOTTOM = 32;
+
+    const QR_HINT_GAP = 14;
+
+    const SCAN_HINT = '微信扫码下单';
+
     /**
      * 海报标题过长时截断,避免压住底部文案区
      */
@@ -44,38 +54,75 @@ class PosterUtil
     }
 
     /**
-     * 按商品图比例计算主图区高度与画布总高
+     * 按商品图比例计算主图区高度与画布总高(能多矮就多矮,仅保留温和下限)
      *
-     * @return array{imgH:int,totalH:int,posterW:int}
+     * @return array{imgH:int,totalH:int,scaledH:int,posterW:int}
      */
     public static function calcPosterLayout($coverWidth, $coverHeight)
     {
         $coverWidth = (int)$coverWidth;
         $coverHeight = (int)$coverHeight;
+        $scaledH = 0;
 
         if ($coverWidth > 0 && $coverHeight > 0) {
             $scaledH = (int)round($coverHeight * (self::SLOT_W / $coverWidth));
             $imgH = max(self::IMG_H_MIN, min(self::IMG_H_MAX, $scaledH));
         } else {
-            $imgH = 720;
+            $imgH = self::IMG_H_MIN;
+            $scaledH = $imgH;
         }
 
         $totalH = $imgH + self::FOOTER_H;
-        $totalH = max(self::TOTAL_H_MIN, min(self::TOTAL_H_MAX, $totalH));
+        $absoluteMin = self::FOOTER_H + 120;
+        $totalH = max($absoluteMin, min(self::TOTAL_H_MAX, $totalH));
 
         return [
             'imgH' => $imgH,
             'totalH' => $totalH,
+            'scaledH' => $scaledH,
             'posterW' => self::POSTER_W,
         ];
     }
 
+    /**
+     * 短图/扁图:lfit 后 pad;长图:m_fill 裁切进槽位
+     */
+    private static function buildCoverWatermarkPath($cover, $imgH, $scaledH, $coverWidth, $coverHeight)
+    {
+        $wide = $coverWidth > 0 && $coverHeight > 0 && ($coverWidth / $coverHeight) > 1.15;
+        $shortSlot = $scaledH > 0 && ($scaledH < $imgH || $wide);
+
+        if ($shortSlot) {
+            return $cover . '?x-oss-process=image/resize,m_lfit,h_' . $imgH . ',w_' . self::SLOT_W . ',limit_0'
+                . '/resize,m_pad,h_' . $imgH . ',w_' . self::SLOT_W . ',color_' . self::CANVAS_COLOR;
+        }
+
+        return $cover . '?x-oss-process=image/resize,m_fill,h_' . $imgH . ',w_' . self::SLOT_W;
+    }
+
+    /**
+     * 太阳码水平中心 X(用于扫码文案 g_south 居中)
+     */
+    private static function qrCenterX()
+    {
+        return self::POSTER_W - self::QR_PAD_RIGHT - (int)(self::QR_SIZE / 2);
+    }
+
+    /**
+     * 扫码提示文案:位于太阳码正上方居中(g_south = 文字下边中点对齐)
+     */
+    private static function scanHintYFromBottom()
+    {
+        return self::QR_PAD_BOTTOM + self::QR_SIZE + self::QR_HINT_GAP;
+    }
+
     /**
      * 动态白底画布(blank.png → 750 × totalH)
      */
     public static function buildCanvasBaseUrl($prefix, $totalH)
     {
-        $totalH = max(self::TOTAL_H_MIN, min(self::TOTAL_H_MAX, (int)$totalH));
+        $absoluteMin = self::FOOTER_H + 120;
+        $totalH = max($absoluteMin, min(self::TOTAL_H_MAX, (int)$totalH));
         $process = '?x-oss-process=image/resize,m_pad,w_' . self::POSTER_W . ',h_' . $totalH
             . ',color_' . self::CANVAS_COLOR;
 
@@ -121,14 +168,11 @@ class PosterUtil
      */
     public static function buildGhsHdItemPosterUrl($prefix, array $options)
     {
-        if (!isset($options['scanHint'])) {
-            $options['scanHint'] = '微信扫码采购';
-        }
         return self::buildMallSharePosterUrl($prefix, $options);
     }
 
     /**
-     * 散客/花束分享海报:动态画布 + 主图固定槽位 + 底部信息区
+     * 散客/花束分享海报:动态画布 + 主图槽位 + 底部信息区
      */
     private static function buildMallSharePosterUrl($prefix, array $options)
     {
@@ -140,7 +184,10 @@ class PosterUtil
         $mainId = (int)($options['mainId'] ?? 0);
         $flowerNum = (int)($options['flowerNum'] ?? 0);
         $subtitle = trim((string)($options['subtitle'] ?? ''));
-        $scanHint = trim((string)($options['scanHint'] ?? '微信扫码下单'));
+        $scanHint = trim((string)($options['scanHint'] ?? self::SCAN_HINT));
+        if ($scanHint === '微信扫码采购') {
+            $scanHint = self::SCAN_HINT;
+        }
 
         $coverW = (int)($options['coverWidth'] ?? 0);
         $coverH = (int)($options['coverHeight'] ?? 0);
@@ -151,6 +198,7 @@ class PosterUtil
         $layout = self::calcPosterLayout($coverW, $coverH);
         $imgH = $layout['imgH'];
         $totalH = $layout['totalH'];
+        $scaledH = $layout['scaledH'];
 
         $displayName = self::truncateText($name, 14);
         if ($flowerNum > 0 && $displayName !== '') {
@@ -159,12 +207,12 @@ class PosterUtil
             $displayName .= ' · ' . self::truncateText($subtitle, 8);
         }
 
-        $coverWatermark = $cover . '?x-oss-process=image/resize,m_fill,h_' . $imgH . ',w_' . self::SLOT_W;
-        $qrWatermark = $miniCode . '?x-oss-process=image/resize,m_fill,h_220,w_220';
+        $coverWatermark = self::buildCoverWatermarkPath($cover, $imgH, $scaledH, $coverW, $coverH);
+        $qrWatermark = $miniCode . '?x-oss-process=image/resize,m_fill,h_' . self::QR_SIZE . ',w_' . self::QR_SIZE;
 
         $url = self::buildCanvasBaseUrl($prefix, $totalH);
         $url .= '/watermark,image_' . stringUtil::ossBase64($coverWatermark) . ',g_north,x_25,y_8';
-        $url .= '/watermark,image_' . stringUtil::ossBase64($qrWatermark) . ',g_se,x_36,y_32';
+        $url .= '/watermark,image_' . stringUtil::ossBase64($qrWatermark) . ',g_se,x_' . self::QR_PAD_RIGHT . ',y_' . self::QR_PAD_BOTTOM;
 
         $logoB64 = self::buildHyxhLogoWatermark($mainId);
         if ($logoB64 !== '') {
@@ -174,7 +222,9 @@ class PosterUtil
         $url .= '/watermark,text_' . stringUtil::ossBase64($priceText) . ',g_sw,x_24,y_32,color_EE2C2C,type_' . self::FONT . ',size_56';
         $url .= '/watermark,text_' . stringUtil::ossBase64($displayName) . ',g_sw,x_24,y_102,color_333333,type_' . self::FONT . ',size_36';
         $url .= '/watermark,text_' . stringUtil::ossBase64($staffText) . ',g_sw,x_24,y_148,color_999999,type_' . self::FONT . ',size_26';
-        $url .= '/watermark,text_' . stringUtil::ossBase64($scanHint) . ',g_se,x_44,y_292,color_888888,type_' . self::FONT . ',size_24';
+        $url .= '/watermark,text_' . stringUtil::ossBase64($scanHint)
+            . ',g_south,x_' . self::qrCenterX() . ',y_' . self::scanHintYFromBottom()
+            . ',color_888888,type_' . self::FONT . ',size_24';
 
         return $url;
     }