前言

本系统通过 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;…