Laravel + Python 圖片水印系統:實現與調試指南

前言

本系統通過 Laravel 作為前端框架接收用戶上傳的圖片,調用 Python 腳本處理水印添加,最終返回處理后的圖片。這種架構充分利用了 Laravel 的便捷性和 Python 圖像處理庫的強大功能。

一、Python 水印處理腳本

from PIL import Image, ImageEnhance
import fitz
import io
import sys
import os
import logging
import traceback# 配置日志記錄
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s',filename='watermark_process.log'
)def compress_image(image, quality=85, max_size=(1920, 1920)):"""壓縮圖片尺寸和質量"""try:if image.size[0] > max_size[0] or image.size[1] > max_size[1]:image.thumbnail(max_size, Image.Resampling.LANCZOS)logging.info(f"圖片已壓縮至尺寸: {image.size}")return imageexcept Exception as e:logging.error(f"圖片壓縮失敗: {str(e)}")raisedef add_watermark_on_top(image_path, pdf_watermark_path, output_path):"""將水印清晰地覆蓋整個圖片"""try:logging.info(f"開始處理圖片: {image_path}")# 檢查文件是否存在if not os.path.exists(image_path):error_msg = f"找不到圖片文件: {image_path}"logging.error(error_msg)raise FileNotFoundError(error_msg)if not os.path.exists(pdf_watermark_path):error_msg = f"找不到水印文件: {pdf_watermark_path}"logging.error(error_msg)raise FileNotFoundError(error_msg)# 打開并壓縮原始圖片base_image = Image.open(image_path)logging.info(f"原始圖片格式: {base_image.format}, 尺寸: {base_image.size}")base_image = compress_image(base_image)# 打開PDF水印pdf_doc = fitz.open(pdf_watermark_path)page = pdf_doc[0]logging.info(f"PDF水印已加載,頁數: {len(pdf_doc)}")# 使用更高分辨率轉換PDF水印mat = fitz.Matrix(8, 8)watermark_pix = page.get_pixmap(matrix=mat, alpha=True)watermark_bytes = watermark_pix.tobytes("png")watermark_image = Image.open(io.BytesIO(watermark_bytes))logging.info(f"水印圖片已轉換,尺寸: {watermark_image.size}")# 確保圖片模式正確if base_image.mode != 'RGBA':base_image = base_image.convert('RGBA')logging.info("原始圖片已轉換為RGBA模式")if watermark_image.mode != 'RGBA':watermark_image = watermark_image.convert('RGBA')logging.info("水印圖片已轉換為RGBA模式")# 將水印調整為與原圖完全相同的尺寸watermark_image = watermark_image.resize(base_image.size, Image.Resampling.LANCZOS)logging.info(f"水印已調整為圖片尺寸: {base_image.size}")# 增強水印的不透明度watermark_data = list(watermark_image.getdata())enhanced_data = []for item in watermark_data:if item[3] > 0:  # 如果像素不是完全透明的enhanced_data.append((item[0], item[1], item[2], min(255, int(item[3] * 2))))else:enhanced_data.append(item)watermark_image.putdata(enhanced_data)logging.info("水印不透明度已增強")# 創建新的圖層并合成result = Image.new('RGBA', base_image.size, (0,0,0,0))result.paste(base_image, (0,0))result.paste(watermark_image, (0,0), watermark_image)logging.info("圖片與水印已合成")# 確保輸出目錄存在output_dir = os.path.dirname(output_path)if not os.path.exists(output_dir):os.makedirs(output_dir, exist_ok=True)logging.info(f"創建輸出目錄: {output_dir}")# 保存結果result.save(output_path, 'PNG', quality=85, optimize=True)logging.info(f"處理后的圖片已保存至: {output_path}")# 關閉PDF文檔pdf_doc.close()return output_pathexcept Exception as e:error_msg = f"處理過程中出現錯誤:{str(e)}"logging.error(error_msg)logging.error(traceback.format_exc())  # 記錄完整的堆棧信息return Nonedef main():try:logging.info("===== 開始新的水印處理任務 =====")if len(sys.argv) != 4:error_msg = "參數數量錯誤,使用方法: python add_watermark.py 輸入圖片路徑 水印PDF路徑 輸出圖片路徑"logging.error(error_msg)print(error_msg)return 1input_image = sys.argv[1]watermark_pdf = sys.argv[2]output_image = sys.argv[3]logging.info(f"接收到命令行參數: 輸入={input_image}, 水印={watermark_pdf}, 輸出={output_image}")result = add_watermark_on_top(input_image, watermark_pdf, output_image)if result:success_msg = f"處理成功,輸出文件:{result}"logging.info(success_msg)print(success_msg)return 0else:error_msg = "處理失敗,詳情請查看日志文件"logging.error(error_msg)print(error_msg)return 1except Exception as e:logging.critical(f"程序崩潰: {str(e)}")logging.critical(traceback.format_exc())print(f"程序異常終止: {str(e)}")return 1if __name__ == "__main__":sys.exit(main())

二、Laravel 后端集成

<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;class WatermarkController extends Controller
{/*** 添加水印到圖片*/public function addWatermark(Request $request){// 驗證請求$request->validate(['image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',]);try {// 存儲上傳的圖片$imagePath = $request->file('image')->store('temp', 'public');$imageFullPath = storage_path('app/public/' . $imagePath);Log::info("圖片已上傳: {$imageFullPath}");// 水印 PDF 路徑$watermarkPdfPath = public_path('watermark.pdf');if (!file_exists($watermarkPdfPath)) {throw new \Exception("水印文件不存在: {$watermarkPdfPath}");}// 準備輸出路徑$outputFileName = 'watermarked_' . time() . '.' . $request->file('image')->extension();$outputPath = 'temp/' . $outputFileName;$outputFullPath = storage_path('app/public/' . $outputPath);// 執行 Python 腳本$pythonPath = env('PYTHON_PATH', 'python3'); // 配置 Python 路徑$scriptPath = base_path('scripts/add_watermark.py');$process = new Process([$pythonPath,$scriptPath,$imageFullPath,$watermarkPdfPath,$outputFullPath]);$process->run();// 檢查執行結果if (!$process->isSuccessful()) {Log::error("Python 腳本執行失敗: " . $process->getErrorOutput());throw new ProcessFailedException($process);}$output = $process->getOutput();Log::info("Python 腳本輸出: {$output}");// 檢查輸出文件是否存在if (!file_exists($outputFullPath)) {throw new \Exception("處理后的圖片不存在,可能 Python 腳本執行失敗");}// 返回處理后的圖片 URL$imageUrl = Storage::url($outputPath);return response()->json(['success' => true,'message' => '水印添加成功','image_url' => $imageUrl]);} catch (\Exception $e) {Log::error("添加水印失敗: " . $e->getMessage());return response()->json(['success' => false,'message' => '處理過程中出錯: ' . $e->getMessage()], 500);}}
}

三、環境配置

在 .env 文件中添加 Python 路徑配置:

PYTHON_PATH=python3  # 根據實際環境修改

四、錯誤調試指南

1. Python 腳本調試

日志文件: 查看 watermark_process.log 獲取詳細處理過程
命令行測試: 直接通過命令行執行 Python 腳本測試

python3 scripts/add_watermark.py /path/to/input.jpg /path/to/watermark.pdf /path/to/output.png

2. Laravel 調試

日志檢查: 查看 storage/logs/laravel.log
異常信息: 捕獲并記錄完整的異常堆棧
權限問題: 確保 storage 目錄可寫
Python 路徑: 確認 .env 中的 PYTHON_PATH 配置正確

3. 常見錯誤及解決方案

錯誤信息可能原因解決方案
找不到圖片文件文件路徑錯誤或權限不足檢查文件路徑和權限
Python 腳本執行失敗Python 環境問題或依賴缺失確認 Python 路徑和依賴(如 PyMuPDF、Pillow)
處理后的圖片不存在Python 腳本內部錯誤查看 Python 日志文件獲取詳細信息

五、部署注意事項

1、Python 依賴安裝:

pip install pillow pymupdf

2、文件權限設置:

chmod -R 755 storage/
chmod -R 755 bootstrap/cache/

3、Nginx 配置:確保上傳文件大小限制足夠大:

client_max_body_size 20M;

通過以上方案,你可以實現一個完整的 Laravel + Python 圖片水印系統,并具備完善的錯誤調試能力。這種架構既發揮了 Laravel 的 Web 開發優勢,又利用了 Python 在圖像處理領域的強大生態。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88692.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88692.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88692.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【速通RAG實戰:企業應用】25、從數智化場景看RAG:是臨時方案,還是終局架構?

引言&#xff1a;RAG為何成為數智化場景的"必爭之地"&#xff1f; 當ChatGPT在2023年掀起生成式AI浪潮時&#xff0c;一個矛盾逐漸凸顯&#xff1a;大語言模型&#xff08;LLM&#xff09;能生成流暢文本&#xff0c;卻常陷入"幻覺"&#xff08;虛構事實&a…

[Python] -實用技巧篇1-用一行Python代碼搞定日常任務

在日常開發或數據處理過程中,我們常常為了一些簡單的小任務寫出數行代碼。但實際上,Python 提供了大量強大且簡潔的語法糖和標準庫工具,讓你用“一行代碼”輕松搞定復雜操作。 本文將通過多個典型場景展示如何用“一行 Python 代碼”高效完成常見任務。 一、文件操作:快速…

單細胞入門(1)——介紹

一、單細胞轉錄組測序流程介紹 單細胞測序能夠探索復雜組織中單個細胞的不同生物學特性&#xff0c;幫助我們認識細胞與細胞之間的差異。這些檢測方法有助于研究細胞譜系、細胞功能、細胞分化、細胞增殖和細胞應答&#xff0c;提升我們對復雜生物系統的理解&#xff0c;包括腫…

數據結構與算法之美:跳表

Hello大家好&#xff01;很高興我們又見面啦&#xff01;給生活添點passion&#xff0c;開始今天的編程之路&#xff01; 我的博客&#xff1a;<但凡. 我的專欄&#xff1a;《編程之路》、《數據結構與算法之美》、《題海拾貝》、《C修煉之路》 歡迎點贊&#xff0c;關注&am…

從0設計一個短鏈接服務:如何實現盡可能短、可變長的短網址系統?

從 0 設計一個短鏈接服務&#xff1a;如何實現盡可能短、可變長的短網址系統&#xff1f; 在日常生活中&#xff0c;我們經常在短信、微博、廣告營銷中看到“短鏈接”&#xff0c;如&#xff1a; https://t.cn/EXaQ4xY https://bit.ly/3Yp9zJk相比冗長復雜的原始 URL&#xff0…

Microsoft Word 中 .doc 和 .docx 的區別

Microsoft Word 中 .doc 和 .docx 的區別 解釋 Microsoft Word 中 .doc 和 .docx 文件格式的區別。這些格式都是 Word 處理文檔的標準&#xff0c;但它們在結構、兼容性和功能上存在顯著差異。下面我將詳細說明。 1. 基本定義 .doc&#xff1a;這是 Microsoft Word 的舊格式&am…

Springboot aop面向切面編程

aop:面向切面編程&#xff0c;理解在一個流程中插入一個切面&#xff0c;這樣切面方法會在指定位置執行能無影響的在某些方法前或者后插入一些動作springboot使用1.引入依賴<dependency><groupId>org.springframework.boot</groupId><artifactId>sprin…

手機識別數據集,2628張原始圖片,支持yolo,coco json,pasical voc xml等格式的標注

本文提供手機識別數據集&#xff0c;2628張原始圖片&#xff0c;支持yolo&#xff0c;coco json,pasical voc xml等格式的標注的數據集下載&#xff0c;下載地址在文末手機識別數據集簡介手機識別數據集通常用于訓練和評估機器學習模型&#xff0c;以識別不同手機品牌、型號或功…

ollama - sqlcoder模型:面向提示詞編程(根據用戶信息生成sql語句并執行返回結果)

https://ollama.ac.cn/library/sqlcoderhttps://blog.csdn.net/hzether/article/details/143816042import ollama import sqlite3 import json from contextlib import closingdef generate_and_execute_sql(question: str, db_path: str) -> dict:# 1. 生成 SQL 查詢語句pr…

C語言,結構體指針案例

案例一&#xff1a; #include <stdio.h> #include <stdbool.h> #include <string.h> // 添加string.h頭文件用于strcpy //結構體指針//方式 1 : 先定義結構體 struct Dog {char *name;int age;char weight; };//方式 1 : char *get_dog_info(struct Dog do…

Vue 3 中父子組件雙向綁定的 4 種方式

&#x1f501; Vue 3 中父子組件雙向綁定的 4 種方式 整理不易&#xff0c;點贊 收藏 關注&#xff0c;助你組件通信不再混亂&#xff01;? 場景說明 父組件希望將某個值傳遞給子組件&#xff0c;同時希望子組件能夠修改這個值&#xff08;實現“綁定 反向更新”&#xff0…

阻有形,容無聲——STA 簽核之RC Corner

RC corner&#xff0c;RC指的是gate跟network的寄生參數&#xff0c;寄生參數抽取工具&#xff08;比如Starrc&#xff09;根據電路的物理信息&#xff0c;抽取出電路的電阻電容值&#xff0c;再以寄生參數文件&#xff08;Spef&#xff09;輸入給STA工具&#xff08;PT&#x…

多代理系統(multi-agent)框架深度解析:架構、特性與未來

在人工智能技術迭代的浪潮中&#xff0c;多代理系統&#xff08;Multi-Agent System&#xff09;正從實驗室走向產業應用的核心舞臺。這一技術范式的崛起源于三大驅動力&#xff1a;大模型能力的指數級提升、復雜任務分解的需求爆發&#xff0c;以及傳統單體智能架構的局限性日…

【Redis】黑馬點評筆記:使用redis解決各種分布式/并發問題

1、系統架構2、基于session登錄用戶的 session 是由服務器&#xff08;如 Tomcat&#xff09;自動管理和維護的&#xff0c;每個用戶在訪問 Web 應用時都會擁有一個獨立的 session 對象。這個對象是通過瀏覽器和服務器之間的 HTTP 協議自動綁定的。1. 如何區分不同用戶的 Sessi…

Javaweb- 11 MVC架構模式

MVC&#xff08;Model View Controller&#xff09; 是軟件工程中一種軟件架構模式&#xff0c;它把軟件系統分為模型&#xff0c;視圖&#xff0c;控制器&#xff0c;三個基本部分。用一種業務邏輯&#xff0c;數據&#xff0c;界面顯示分離的方法組織代碼&#xff0c;將業務邏…

【電腦】主板的基礎知識

主板&#xff08;Motherboard&#xff09;是計算機的核心組件之一&#xff0c;它將所有其他硬件部件連接在一起并協調它們的工作。以下是關于主板的詳細知識&#xff1a;1. 架構組成一個典型的主板通常由以下幾個主要部分構成&#xff1a;芯片組&#xff08;Chipset&#xff09…

【飛算JavaAI】一站式智能開發,驅動Java開發全流程革新

【作者主頁】Francek Chen 【專欄介紹】???人工智能與大模型應用??? 人工智能&#xff08;AI&#xff09;通過算法模擬人類智能&#xff0c;利用機器學習、深度學習等技術驅動醫療、金融等領域的智能化。大模型是千億參數的深度神經網絡&#xff08;如ChatGPT&#xff09…

STM32中的RTC(實時時鐘)詳解

前言&#xff1a;為什么需要RTC&#xff1f; 在嵌入式系統中&#xff0c;時間記錄是一項基礎且關鍵的功能。想象一下&#xff1a;智能家居設備需要按時間觸發開關燈&#xff0c;工業儀表需要記錄傳感器數據的采集時刻&#xff0c;物聯網終端需要同步服務器時間戳……這些場景都…

Python技巧記錄

空格拼接數組格式化顯示 一維數組 arr [1, 2, 3, 4, 5] print( .join(map(str, arr))) # 直接轉換并連接二維數組 for row in arr:print( .join(map(str, row)))for row in arr: 此循環會遍歷矩陣arr中的每一行。這里的arr是一個二維列表&#xff0c;每一行代表一個子列表。m…

next.js打包后的前端資源如何進行部署和訪問,為什么沒有index.html

在 Next.js 項目中&#xff0c;打包后的部署方式和傳統單頁應用&#xff08;SPA&#xff09;有所不同&#xff0c;尤其是沒有直接生成 index.html 這一點。以下是詳細解釋和部署指南&#xff1a;為什么沒有 index.html 文件&#xff1f; Next.js 采用 混合渲染策略&#xff0c;…