liuhairui 5 сар өмнө
parent
commit
5dcad78d1f

+ 38 - 30
application/api/controller/WorkOrder.php

@@ -28,51 +28,59 @@ class WorkOrder extends Api
 
 
     /**
-     * 图生图
-     * /sdapi/v1/img2img
+     * 图生图功能 - /sdapi/v1/img2img
      */
     public function imgtowimg()
     {
-        $prompt = $this->request->param('prompt', '');
-        $denoising = (float)$this->request->param('denoising_strength', 0.2);
-        $scale = (float)$this->request->param('scale', 2.0);
-        $modelName = $this->request->param('model', 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]');
-
-        // 原图路径
+        $prompt = $this->request->param('prompt', ''); // 用户传入的提示词
         $imgRelPath = 'uploads/operate/ai/Preview/arr/0828004096727.png';
         $imgPath = ROOT_PATH . 'public/' . $imgRelPath;
 
+        // 校验原图是否存在
         if (!file_exists($imgPath)) {
             return json(['code' => 1, 'msg' => '原图不存在:' . $imgRelPath]);
         }
 
-        // 获取原图尺寸 × 倍数
-        list($originW, $originH) = getimagesize($imgPath);
-        $targetW = intval($originW * $scale);
-        $targetH = intval($originH * $scale);
-
-        // base64 编码
+        // -------- 固定参数定义 -------- //
+        $denoising = 0.6;                            // 重绘幅度(图像改动程度,0 = 很小变化,1 = 几乎全新图像)
+        $steps = 20;                                 // 迭代步数(采样次数,值越大越精细)
+        $cfgScale = 7;                               // 提示词引导系数(越高越贴近提示词)
+        $clipSkip = 7;                               // 跳过 CLIP 编码器层数(影响风格细节)
+        $sampler = 'DPM++ 2M SDE Heun';              // 使用的采样器算法
+        $modelName = 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]'; // 使用的 SD 模型
+        $vaeName = 'anything-v4.5.vae.pt';           // 外挂 VAE(色彩、对比度增强)
+        $seed = 611075477;                           // 固定随机种子(可复现)
+        $targetW = 1024;                             // 输出图像宽度
+        $targetH = 2048;                             // 输出图像高度
+
+        // -------- 图像编码为 base64 -------- //
         $imgData = file_get_contents($imgPath);
         $base64Img = base64_encode($imgData);
         $initImage = 'data:image/png;base64,' . $base64Img;
 
-        // 请求体
+        // -------- 构建 POST 请求体 -------- //
         $postData = json_encode([
-            'prompt' => $prompt,
-            'steps' => 30,
-            'cfg_scale' => 7,
-            'denoising_strength' => $denoising,
-            'width' => $targetW,
-            'height' => $targetH,
-            'resize_mode' => 1,
-            'inpaint_full_res' => true,
-            'inpainting_fill' => 1,
-            'init_images' => [$initImage],
-            'override_settings' => [
-                'sd_model_checkpoint' => $modelName
-            ]
+            'prompt' => $prompt,                     // 提示词
+            'steps' => $steps,                       // 迭代步数
+            'cfg_scale' => $cfgScale,                // 提示词引导强度
+            'denoising_strength' => $denoising,      // 重绘幅度
+            'width' => $targetW,                     // 输出图像宽度
+            'height' => $targetH,                    // 输出图像高度
+            'resize_mode' => 2,                      // 缩放模式:2 = 缩放后填充空白
+            'sampler_name' => $sampler,              // 采样算法
+            'seed' => $seed,                         // 随机种子
+            'inpaint_full_res' => true,              // 使用原始分辨率处理 inpaint
+            'inpainting_fill' => 1,                  // 背景填充模式:1 = 灰色
+            'init_images' => [$initImage],           // 输入图像(base64)
+            'override_settings' => [                 // 覆盖默认模型设置
+                'sd_model_checkpoint' => $modelName, // 使用的模型
+                'sd_vae' => $vaeName,                // 外挂 VAE 文件
+                'CLIP_stop_at_last_layers' => $clipSkip // clip 跳过层
+            ],
+            'override_settings_restore_afterwards' => true // 调用后恢复模型设置
         ]);
 
+        // -------- 发送请求到 SD API -------- //
         $apiUrl = "http://20.0.17.233:45001/sdapi/v1/img2img";
         $headers = ['Content-Type: application/json'];
 
@@ -96,7 +104,7 @@ class WorkOrder extends Api
             return json(['code' => 1, 'msg' => '接口未返回图像数据']);
         }
 
-        // 保存图像:原图名 + -1
+        // -------- 保存生成图像 -------- //
         $resultImg = base64_decode($data['images'][0]);
         $saveDir = ROOT_PATH . 'public/uploads/img2img/';
         if (!is_dir($saveDir)) {
@@ -104,7 +112,7 @@ class WorkOrder extends Api
         }
 
         $originalBaseName = pathinfo($imgRelPath, PATHINFO_FILENAME);
-        $fileName = $originalBaseName . '-1.png';
+        $fileName = $originalBaseName . '-' . time() . '-1.png';
         $savePath = $saveDir . $fileName;
         file_put_contents($savePath, $resultImg);
 

+ 120 - 17
application/job/ImageToImageJob.php

@@ -56,8 +56,9 @@ class ImageToImageJob{
                         $data["file_name"],
                         $data["outputDir"],
                         $row["new_image_url"],
-                        1024,
-                        2048
+                        $row["img_name"],
+                        679,
+                        862
                     );
 
                     $resultText = ($result === true || $result === 1 || $result === '成功') ? '成功' : '失败或无返回';
@@ -123,8 +124,7 @@ class ImageToImageJob{
         echo "ImageJob failed: " . json_encode($data);
     }
 
-
-    public function ImageToImage($fileName, $outputDirRaw, $new_image_url, $width, $height)
+    public function ImageToImage($fileName, $outputDirRaw, $new_image_url,$img_name, $width, $height)
     {
         // 统一路径分隔符
         $rootPath = str_replace('\\', '/', ROOT_PATH);
@@ -138,11 +138,10 @@ class ImageToImageJob{
         // 完整基本路径,如:ROOT/public/uploads/operate/ai/dall-e/hua/2025-06-16/
         $fullBaseDir = $outputDir . $dateDir;
 
-        // 创建输出目录,包括原图目录、1024x2048目录、自定义尺寸目录
-        foreach ([$fullBaseDir, $fullBaseDir . '1024x2048/', $fullBaseDir . "{$width}x{$height}/"] as $dir) {
-            if (!is_dir($dir)) {
-                mkdir($dir, 0755, true);
-            }
+        // 只创建 img_679x862 目录
+        $saveDir = $fullBaseDir . 'new_679x862/';
+        if (!is_dir($saveDir)) {
+            mkdir($saveDir, 0755, true);
         }
 
         // 从数据库中查询原图记录
@@ -170,18 +169,55 @@ class ImageToImageJob{
             ]);
         }
 
+        // 保存图片路径
+        $img_name = mb_substr(preg_replace('/[^\x{4e00}-\x{9fa5}A-Za-z0-9_\- ]/u', '', $img_name), 0, 30);
+        $filename = $img_name . '.png';
+        $path = $saveDir . $filename;
+
         // 解码图像 base64 数据
-        $originalBaseName = pathinfo($new_image_url, PATHINFO_FILENAME);
-        $finalFileName = $originalBaseName . '.png';
+        $imgData = base64_decode($res['data']['url']);
+
+        // 解析图像内容
+        try {
+            $im = \imagecreatefromstring($imgData);
+            if (!$im) {
+                file_put_contents('/tmp/corrupted.png', $imgData);
+                throw new \Exception("❌ 图像无法解析,写入 /tmp/corrupted.png");
+            }
+        } catch (\Throwable $e) {
+            file_put_contents('/tmp/corrupted.png', $imgData);
+            throw new \Exception("❌ 图像处理异常:" . $e->getMessage());
+        }
+
+        // 裁剪
+        $srcW = imagesx($im);
+        $srcH = imagesy($im);
+        $srcRatio = $srcW / $srcH;
+        $dstRatio = $width / $height;
+
+        if ($srcRatio > $dstRatio) {
+            $cropW = intval($srcH * $dstRatio);
+            $cropH = $srcH;
+            $srcX = intval(($srcW - $cropW) / 2);
+            $srcY = 0;
+        } else {
+            $cropW = $srcW;
+            $cropH = intval($srcW / $dstRatio);
+            $srcX = 0;
+            $srcY = intval(($srcH - $cropH) / 2);
+        }
 
-        // 保存到 1024x2048 子目录
-        $targetDir = $fullBaseDir . '1024x2048/';
-        $savePath = $targetDir . $finalFileName;
-        file_put_contents($savePath, base64_decode($res['data']['url']));
+        $dstImg = imagecreatetruecolor($width, $height);
+        imagecopyresampled($dstImg, $im, 0, 0, $srcX, $srcY, $width, $height, $cropW, $cropH);
 
-        // ✅ 修正:数据库中记录相对路径一致
+        // 保存裁剪图
+        imagepng($dstImg, $path);
+        imagedestroy($im);
+        imagedestroy($dstImg);
+
+        // 更新数据库记录
         Db::name('text_to_image')->where('id', $record['id'])->update([
-            'imgtoimg_url' => $outputDirRaw . '/' . $dateDir . '1024x2048/' . $finalFileName,
+            'imgtoimg_url' => str_replace($rootPath . 'public/', '', $path),
             'status_name' => '图生图',
             'error_msg' => '',
             'update_time' => date('Y-m-d H:i:s')
@@ -190,4 +226,71 @@ class ImageToImageJob{
         return '成功';
     }
 
+
+//    public function ImageToImage($fileName, $outputDirRaw, $new_image_url, $width, $height)
+//    {
+//        // 统一路径分隔符
+//        $rootPath = str_replace('\\', '/', ROOT_PATH);
+//
+//        // 输出目录,如:ROOT/public/uploads/operate/ai/dall-e/hua/
+//        $outputDir = rtrim($rootPath . 'public/' . $outputDirRaw, '/') . '/';
+//
+//        // 当前日期目录,如:2025-06-16/
+//        $dateDir = date('Y-m-d') . '/';
+//
+//        // 完整基本路径,如:ROOT/public/uploads/operate/ai/dall-e/hua/2025-06-16/
+//        $fullBaseDir = $outputDir . $dateDir;
+//
+//        // 创建输出目录,包括原图目录、1024x2048目录、自定义尺寸目录
+//        foreach ([$fullBaseDir, $fullBaseDir . '1024x2048/', $fullBaseDir . "{$width}x{$height}/"] as $dir) {
+//            if (!is_dir($dir)) {
+//                mkdir($dir, 0755, true);
+//            }
+//        }
+//
+//        // 从数据库中查询原图记录
+//        $record = Db::name('text_to_image')
+//            ->where('old_image_url', 'like', "%{$fileName}")
+//            ->order('id desc')
+//            ->find();
+//
+//        if (!$record) {
+//            return json([
+//                'code' => 1,
+//                'msg' => '没有找到匹配的图像记录'
+//            ]);
+//        }
+//
+//        // 调用图生图 API
+//        $ai = new AIGatewayService();
+//        $res = $ai->imgtoimgGptApi('', $new_image_url);
+//
+//        // 检查返回结果
+//        if (!isset($res['code']) || $res['code'] !== 0) {
+//            return json([
+//                'code' => 1,
+//                'msg' => $res['msg'] ?? '图像生成失败'
+//            ]);
+//        }
+//
+//        // 解码图像 base64 数据
+//        $originalBaseName = pathinfo($new_image_url, PATHINFO_FILENAME);
+//        $finalFileName = $originalBaseName . '.png';
+//
+//        // 保存到 1024x2048 子目录
+//        $targetDir = $fullBaseDir . '1024x2048/';
+//        $savePath = $targetDir . $finalFileName;
+//        file_put_contents($savePath, base64_decode($res['data']['url']));
+//
+//        // ✅ 修正:数据库中记录相对路径一致
+//        Db::name('text_to_image')->where('id', $record['id'])->update([
+//            'imgtoimg_url' => $outputDirRaw . '/' . $dateDir . '1024x2048/' . $finalFileName,
+//            'status_name' => '图生图',
+//            'error_msg' => '',
+//            'update_time' => date('Y-m-d H:i:s')
+//        ]);
+//
+//        return '成功';
+//    }
+
 }

+ 10 - 6
application/service/AIGatewayService.php

@@ -186,24 +186,28 @@ class AIGatewayService{
         $base64Img = base64_encode($imgData);
         $initImage = 'data:image/png;base64,' . $base64Img;
 
-        // 构建 POST 请求参数
+        //请求参数
         $postData = json_encode([
             'prompt' => $prompt,
-            'sampler_name' => 'DPM++ 2M SDE Heun',
-            'seed' => -1,
             'steps' => 20,
             'cfg_scale' => 7,
             'denoising_strength' => 0.6,
             'width' => 1024,
             'height' => 2048,
-            'resize_mode' => 0,
+//            'width' => 679,
+//            'height' => 862,
+            'resize_mode' => 2,
+            'sampler_name' => 'DPM++ 2M SDE Heun',
+            'seed' => -1,
             'inpaint_full_res' => true,
             'inpainting_fill' => 1,
             'init_images' => [$initImage],
             'override_settings' => [
                 'sd_model_checkpoint' => 'realisticVisionV51_v51VAE-inpainting.safetensors [f0d4872d24]',
-                'sd_vae' => 'anything-v4.5.vae.pt'
-            ]
+                'sd_vae' => 'anything-v4.5.vae.pt',
+                'CLIP_stop_at_last_layers' => 7
+            ],
+            'override_settings_restore_afterwards' => true // 调用后恢复模型设置
         ]);
 
         $apiUrl = "http://20.0.17.233:45001/sdapi/v1/img2img";