照片边框添加 | Python | 免费无广告

news2024/11/20 2:45:08

演示图

在这里插入图片描述

在这里插入图片描述
请添加图片描述
请添加图片描述
在这里插入图片描述

说明

照片边框添加 | Python | 免费无广告
🔅理论上Mac及Windos都可运行,只需要python环境即可~~~

🔅目前提供了两种样式,白色边框以及透明边框:P2是原图,P3是白色边框的效果,P4是透明边框效果。

🔅使用方法如下:
(一)将需要添加边框的照片放入到【images_input】文件夹中,一次可添加多张,如P5所示。
(二)在该文件夹下运行python代码:①python3 WorT.py W可为图片添加白色边框。②python3 WorT.py T可为图片添加透明边框。
(三)从images_output中获取结果!

🔅声明:给照片添加边框的创意早已存在,本人在收集整理前人代码(酷安、CSDN、GPT)的基础上优化生成更加【方便、好用】的新代码,并且【免费】分享给大家,后期有空也会继续迭代升级~~~~

代码

代码如下,绑定的资源文件请自行下载:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import exifread
import os
from fractions import Fraction
from PIL import Image, ImageDraw, ImageFont, ImageOps, ImageFilter
import shutil
import argparse

# 遍历文件夹处理
def watermark(srcPath, distPath,color):
    # 遍历文件夹
    for filename in os.listdir(srcPath):
        # 目录验证
        if not os.path.exists(distPath):
            os.makedirs(distPath)
        # 拼接完整的文件或文件夹路径
        srcFile = os.path.join(srcPath, filename)
        distFile = os.path.join(distPath, filename)

        # 如果是文件 就调用exinfo
        if os.path.isfile(srcFile):
            if is_image(srcFile):
                # 执行压缩操作
                imageprocess(srcFile, distFile, color)
            else:
                print(" 文件不是图片,跳过!")
        # 如果是文件夹 就继续递归
        elif os.path.isdir(srcFile):
            watermark(srcFile, distPath)


# 文件是否为图片判断
def is_image(srcFile):
    return srcFile.lower().endswith(('.png', '.jpg', '.jpeg', '.tif', '.tiff'))


# 开始处理图片
def imageprocess(srcFile,distFile,color):
    if color == "T": #透明的
        imageprocess2(srcFile,distFile)
    else:
        try:
            tags = exifread.process_file(open(srcFile, 'rb'))  # 获取照片的exif信息并更新需要写入的文字

        except:
            print("出错跳过")

        else:
            品牌 = ""
            机型 = ""
            镜头 = ""
            logo_img = "logo/SONY.png"
            快门 = ""
            ISO = ""
            光圈 = ""
            焦距 = ""
            if 'EXIF ISOSpeedRatings' in tags.keys():
                ISO = "ISO" + str(tags['EXIF ISOSpeedRatings'])
            if 'Image Make' in tags.keys():
                品牌 = str(tags['Image Make'])
            if 'Image Model' in tags.keys():
                机型 = str(tags['Image Make']) + " " + str(tags['Image Model'])
            if 'EXIF FNumber' in tags.keys():
                fnum = float(Fraction(str(tags['EXIF FNumber'])))
                光圈 = "f/" + str(fnum)

            if 'EXIF ExposureTime' in tags.keys():
                speed = Fraction(str(tags['EXIF ExposureTime']))
                快门 = str(speed)

            if 'EXIF FocalLengthIn35mmFilm' in tags.keys():
                焦距 = str(tags['EXIF FocalLengthIn35mmFilm']) + "mm"
            else:
                焦距 = str(tags['EXIF FocalLength']) + "mm"
            if 'EXIF LensModel' in tags.keys():
                镜头 = str(tags['EXIF LensModel'])
            else:
                镜头 = ""

            # 选择logo
            if 品牌 == "SONY":
                logo_img = "logo/SONY.png"

            if 品牌 == "Panasonic":
                logo_img = "logo/Lumix.png"

                if 'Exif.Panasonic.LensType' in tags.keys():
                    镜头 = str(tags['EXIF LensModel'])
                else:
                    镜头 = ""

            if 品牌 == "vivo":
                logo_img = "logo/ZEISS.png"
                机型 = str(tags['Image Model'])
                extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
                快门 = str(extime)

            if 品牌 == "Canon":
                logo_img = "logo/Canon.png"
                机型 = str(tags['Image Model'])

            if 品牌 == "NIKON CORPORATION":
                logo_img = "logo/NIKON-2.png"
                机型 = str(tags['Image Model'])

            if 品牌 == "Xiaomi":
                logo_img = "logo/leica.png"
                机型 = str(tags['Image Model'])
                if 机型 == "M2006J10C":
                    length = float(Fraction(str(tags['EXIF FocalLength'])))
                    焦距 = str(length) + "mm"
                    extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
                    快门 = str(extime)

            if 品牌 == "Google":
                logo_img = "logo/Google.png"
                extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
                快门 = str(extime)

            if 品牌 == "PENTAX":
                logo_img = "logo/PENTAX.png"
                机型 = str(tags['Image Model'])

            if 品牌 == "RICOH":
                logo_img = "logo/PENTAX.png"

            if 品牌 == "FUJIFILM":
                logo_img = "logo/FUJIFILM.png"

            if 品牌 == "GoPro":
                logo_img = "logo/GoPro.png"

            if 品牌 == "Olympus":
                logo_img = "logo/Olympus.png"

            if 品牌 == "PhaseOne":
                logo_img = "logo/PhaseOne.png"

            if 品牌 == "Hasselblad":
                logo_img = "logo/Hasselblad.png"

            if 品牌 == "HUAWEI":
                logo_img = "logo/HUAWEI.png"

            焦段 = 焦距 + "   " + 光圈 + "   " + 快门 + "   " + ISO

            # 打开原始照片
            待处理照片 = Image.open(srcFile)
            待处理照片 = ImageOps.exif_transpose(待处理照片)
            待处理照片宽, 待处理照片高 = 待处理照片.size

            # ========可设定参数
            背景边框宽度 = 600
            背景边框高度 = 500
            高斯数值 = 15

            #=========样式优化
            水印横向偏置 = 待处理照片宽 / 8
            
            # # 创建模糊背景
            # 模糊背景 = 待处理照片.copy()
            # 模糊背景 = 模糊背景.filter(ImageFilter.GaussianBlur(高斯数值))
            # 模糊背景 = 模糊背景.resize((待处理照片宽 + 背景边框宽度, 待处理照片高 + 背景边框高度), Image.Resampling.LANCZOS)

            # 创建一个比原始照片大一些的新图像,添加模糊背景边框
            背景图 = Image.new('RGB', (待处理照片宽 + 背景边框宽度, 待处理照片高 + 背景边框高度), (255, 255, 255))
            # 背景图.paste(模糊背景, (0, 0))

            # 计算图片粘贴位置使其居中
            paste_x = (背景图.width - 待处理照片宽) // 2
            paste_y = (背景图.height - 待处理照片高 - 170) // 2  # 留出空间放水印
            背景图.paste(待处理照片, (paste_x, paste_y))

            # 在模糊背景上绘制水印
            draw = ImageDraw.Draw(背景图)
            # 绘制三段文字
            font1 = ImageFont.truetype("font/Siemens Sans Bold.ttf", 84)
            font2 = ImageFont.truetype("font/msyh.ttc", 60)
            font3 = ImageFont.truetype("font/msyh.ttc", 78)
            draw.text((paste_x + 水印横向偏置, paste_y + 待处理照片高 + 54), 机型, fill=(0, 0, 0, 255), font=font1) #164
            draw.text((paste_x + 水印横向偏置, paste_y + 待处理照片高 + 154), 镜头, fill=(122, 122, 122, 255), font=font2)#164
            draw.text((paste_x + 待处理照片宽 - 水印横向偏置 - 1000, paste_y + 待处理照片高 + 99), 焦段, fill=(0, 0, 0, 255), font=font3)#2708    焦段、光圈、iso信息;1000是这行字的宽度
            # 绘制分隔线
            分割线偏置 = 待处理照片宽 - 水印横向偏置 - 1000 - 54 #54是上面这段字和分隔线的距离
            draw.line(((paste_x + 分割线偏置, paste_y + 待处理照片高 + 64), (paste_x + 分割线偏置, paste_y + 待处理照片高 + 236)), (197, 197, 197, 255), width=6)#2644 比上面小54

            # 通过图片绘制logo
            图标偏置 = int(分割线偏置 - 54 - 185)
            if 机型 != "":
                logo = Image.open(logo_img)
                logo图片宽, logo图片高 = logo.size
                if logo图片宽 > logo图片高:
                    背景图.paste(logo, (paste_x + 图标偏置, paste_y + 待处理照片高 + 62)) #2300
                else:
                    背景图.paste(logo, (paste_x + 图标偏置, paste_y + 待处理照片高 + 62))

            背景图.save(distFile, quality=100, exif=待处理照片.info['exif'])
            print(srcFile, "已处理完成")

def imageprocess2(srcFile, distFile):
    try:
        tags = exifread.process_file(open(srcFile, 'rb'))  # 获取照片的exif信息并更新需要写入的文字

    except:
        print("出错跳过")

    else:
        品牌 = ""
        机型 = ""
        镜头 = ""
        logo_img = "logo/SONY.png"
        快门 = ""
        ISO = ""
        光圈 = ""
        焦距 = ""
        if 'EXIF ISOSpeedRatings' in tags.keys():
            ISO = "ISO" + str(tags['EXIF ISOSpeedRatings'])
        if 'Image Make' in tags.keys():
            品牌 = str(tags['Image Make'])
        if 'Image Model' in tags.keys():
            机型 = str(tags['Image Make']) + " " + str(tags['Image Model'])
        if 'EXIF FNumber' in tags.keys():
            fnum = float(Fraction(str(tags['EXIF FNumber'])))
            光圈 = "f/" + str(fnum)

        if 'EXIF ExposureTime' in tags.keys():
            speed = Fraction(str(tags['EXIF ExposureTime']))
            快门 = str(speed)

        if 'EXIF FocalLengthIn35mmFilm' in tags.keys():
            焦距 = str(tags['EXIF FocalLengthIn35mmFilm']) + "mm"
        else:
            焦距 = str(tags['EXIF FocalLength']) + "mm"
        if 'EXIF LensModel' in tags.keys():
            镜头 = str(tags['EXIF LensModel'])
        else:
            镜头 = ""

        # 选择logo
        if 品牌 == "SONY":
            logo_img = "logo/SONY.png"

        if 品牌 == "Panasonic":
            logo_img = "logo/Lumix.png"

            if 'Exif.Panasonic.LensType' in tags.keys():
                镜头 = str(tags['EXIF LensModel'])
            else:
                镜头 = ""

        if 品牌 == "vivo":
            logo_img = "logo/ZEISS.png"
            机型 = str(tags['Image Model'])
            extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
            快门 = str(extime)

        if 品牌 == "Canon":
            logo_img = "logo/Canon.png"
            机型 = str(tags['Image Model'])

        if 品牌 == "NIKON CORPORATION":
            logo_img = "logo/NIKON-2.png"
            机型 = str(tags['Image Model'])

        if 品牌 == "Xiaomi":
            logo_img = "logo/leica.png"
            机型 = str(tags['Image Model'])
            if 机型 == "M2006J10C":
                length = float(Fraction(str(tags['EXIF FocalLength'])))
                焦距 = str(length) + "mm"
                extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
                快门 = str(extime)

        if 品牌 == "Google":
            logo_img = "logo/Google.png"
            extime = Fraction(str(tags['EXIF ExposureTime'])).limit_denominator(300)
            快门 = str(extime)

        if 品牌 == "PENTAX":
            logo_img = "logo/PENTAX.png"
            机型 = str(tags['Image Model'])

        if 品牌 == "RICOH":
            logo_img = "logo/PENTAX.png"

        if 品牌 == "FUJIFILM":
            logo_img = "logo/FUJIFILM.png"

        if 品牌 == "GoPro":
            logo_img = "logo/GoPro.png"

        if 品牌 == "Olympus":
            logo_img = "logo/Olympus.png"

        if 品牌 == "PhaseOne":
            logo_img = "logo/PhaseOne.png"

        if 品牌 == "Hasselblad":
            logo_img = "logo/Hasselblad.png"

        if 品牌 == "HUAWEI":
            logo_img = "logo/HUAWEI.png"

        焦段 = 焦距 + "   " + 光圈 + "   " + 快门 + "   " + ISO

        # 打开原始照片
        待处理照片 = Image.open(srcFile)
        待处理照片 = ImageOps.exif_transpose(待处理照片)
        待处理照片宽, 待处理照片高 = 待处理照片.size

        # ========可设定参数
        背景边框宽度 = 600
        背景边框高度 = 500
        高斯数值 = 15

        #=========样式优化
        水印横向偏置 = 待处理照片宽 / 8
        

        # 创建模糊背景
        模糊背景 = 待处理照片.copy()
        模糊背景 = 模糊背景.filter(ImageFilter.GaussianBlur(高斯数值))
        模糊背景 = 模糊背景.resize((待处理照片宽 + 背景边框宽度, 待处理照片高 + 背景边框高度), Image.Resampling.LANCZOS)

        # 创建一个比原始照片大一些的新图像,添加模糊背景边框
        背景图 = Image.new('RGB', (待处理照片宽 + 背景边框宽度, 待处理照片高 + 背景边框高度))
        背景图.paste(模糊背景, (0, 0))

        # 计算图片粘贴位置使其居中
        paste_x = (背景图.width - 待处理照片宽) // 2
        paste_y = (背景图.height - 待处理照片高 - 170) // 2  # 留出空间放水印
        背景图.paste(待处理照片, (paste_x, paste_y))

        # 在模糊背景上绘制水印
        draw = ImageDraw.Draw(背景图)
        # 绘制三段文字
        font1 = ImageFont.truetype("font/Siemens Sans Bold.ttf", 84)
        font2 = ImageFont.truetype("font/msyh.ttc", 60)
        font3 = ImageFont.truetype("font/msyh.ttc", 78)
        draw.text((paste_x + 水印横向偏置, paste_y + 待处理照片高 + 54), 机型, fill=(255, 255, 255, 255), font=font1) #164
        draw.text((paste_x + 水印横向偏置, paste_y + 待处理照片高 + 154), 镜头, fill=(255, 255, 255, 255), font=font2)#164
        draw.text((paste_x + 待处理照片宽 - 水印横向偏置 - 1000, paste_y + 待处理照片高 + 99), 焦段, fill=(255, 255, 255, 255), font=font3)#2708    焦段、光圈、iso信息;1000是这行字的宽度
        # 绘制分隔线
        分割线偏置 = 待处理照片宽 - 水印横向偏置 - 1000 - 54 #54是上面这段字和分隔线的距离
        draw.line(((paste_x + 分割线偏置, paste_y + 待处理照片高 + 64), (paste_x + 分割线偏置, paste_y + 待处理照片高 + 236)), (197, 197, 197, 255), width=6)#2644 比上面小54

        # 通过图片绘制logo
        图标偏置 = int(分割线偏置 - 54 - 185)
        if 机型 != "":
            logo = Image.open(logo_img)
            logo图片宽, logo图片高 = logo.size
            if logo图片宽 > logo图片高:
                背景图.paste(logo, (paste_x + 图标偏置, paste_y + 待处理照片高 + 62)) #2300
            else:
                背景图.paste(logo, (paste_x + 图标偏置, paste_y + 待处理照片高 + 62))

        背景图.save(distFile, quality=100, exif=待处理照片.info['exif'])
        print(srcFile, "已处理完成")



if __name__ == '__main__':
    srcPath = 'images_intput'
    distPath = 'images_output'
    wrongpath = 'wrong'
    parser = argparse.ArgumentParser(description="Add watermark to images")
    parser.add_argument('color', type=str, help="Specify the border color (e.g., 'white')")
    args = parser.parse_args()
    color = args.color
    watermark(srcPath, distPath, color)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1899697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python: create Envircomnet in Visual Studio Code 创建虚拟环境

先配置python开发环境 1.在搜索栏输入“>" 或是用快捷组合键ctrlshiftP键 就会显示”>",再输入"python:" 选择已经安装好的python的版本,选定至当前项目中,都是按回车 就可以看到创建了一个虚拟环境的默认的文件夹名".venv" 2 …

动手学深度学习(Pytorch版)代码实践 -循环神经网络-53语言模型和数据集

53语言模型和数据集 1.自然语言统计 引入库和读取数据: import random import torch from d2l import torch as d2l import liliPytorch as lp import numpy as np import matplotlib.pyplot as plttokens lp.tokenize(lp.read_time_machine())一元语法&#xf…

FreeBSD@ThinkPad x250因电池耗尽关机后无法启动的问题存档

好几次碰到电池耗尽FreeBSD关机,再启动,网络通了之后到了该出Xwindows窗体的时候,屏幕灭掉,网络不通,只有风扇在响,启动失败。关键是长按开关键后再次开机,还是启动失败。 偶尔有时候重启到单人…

前端面试题16(跨域问题)

跨域问题源于浏览器的同源策略(Same-origin policy),这一策略限制了来自不同源的“写”操作(比如更新、删除数据等),同时也限制了读操作。当一个网页尝试请求与自身来源不同的资源时,浏览器会阻…

Redis基础教程(七):redis列表(List)

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

Python酷库之旅-第三方库Pandas(005)

目录 一、用法精讲 7、pandas.read_clipboard函数 7-1、语法 7-2、参数 7-3、功能 7-4、返回值 7-5、说明 7-6、用法 7-6-1、代码示例 7-6-2、结果输出 8、pandas.DataFrame.to_clipboard函数 8-1、语法 8-2、参数 8-3、功能 8-4、返回值 8-5、说明 8-6、用法…

LivePortrait:一张照片生成生动视频,精准操控眼睛和嘴唇动作 本地一键整合包下载

LivePortrait,这个名字听起来就像是魔法,但它其实是现实世界中的黑科技。想象一下,你那尘封已久的相册里,那些定格在时间里的笑脸,突然间动了起来,眨眼、微笑、甚至说话,这不再是电影里的场景&a…

三相感应电机的建模仿真(2)基于ABC相坐标系S-Fun的仿真模型

1. 概述 2. 三相感应电动机状态方程式 3. 基于S-Function的仿真模型建立 4. 瞬态分析实例 5. 总结 6. 参考文献 1. 概述 前面建立的三相感应电机在ABC相坐标系下的数学模型是一组周期性变系数微分方程(其电感矩阵是转子位置角的函数,转子位置角随时…

DAY20-力扣刷题

1.填充每个节点的下一个右侧节点指针 116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode) 方法一:层次遍历 class Solution {public Node connect(Node root) {if (root null) {return root;}// 初始化队列同时将第一层节点加入队列…

【网络管理工具】NETworkManager工具的基本使用教程

【网络管理工具】NETworkManager工具的基本使用教程 一、NETworkManager工具介绍1.1 NETworkManager简介1.2 NETworkManager特点1.3 NETworkManager使用场景 二、下载NETworkManager软件包2.1 下载地址2.2 下载软件 三、运行NETworkManager工具3.1 解压NETworkManager3.2 运行N…

搭建排查tomcat内存溢出问题的调试环境

上个月赶工上线的门户网站,由于种种原因导致部署到线上服务器后每隔一段时间后就会导致tomcat内存溢出,今天我就要来直面这个棘手的问题。 要解决的问题对我来说还是有点难度的,原因有二: 代码不是我写的;我对java并不…

【操作与配置】VSCode配置Python及Jupyter

Python环境配置 可以参见:【操作与配置】Python:CondaPycharm_pycharmconda-CSDN博客 官网下载Python:http://www.python.org/download/官网下载Conda:Miniconda — Anaconda documentation VSCode插件安装 插件安装后需重启V…

14-28 剑和诗人2 - 高性能编程Bend和Mojo

介绍: 在不断发展的计算世界中,软件和硬件之间的界限变得越来越模糊。随着我们不断突破技术可能性的界限,对能够利用现代硬件功能的高效、可扩展的编程语言的需求从未如此迫切。 Bend和 Mojo是编程语言领域的两种新秀,它们有望弥…

HumbleBundle7月虚幻捆绑包30件军事题材美术模型沙漠自然环境大逃杀模块化建筑可定制武器包二战现代坦克飞机道具丧尸士兵角色模型20240705

HumbleBundle7月虚幻捆绑包30件军事题材美术模型沙漠自然环境大逃杀模块化建筑可定制武器包二战现代坦克飞机道具丧尸士兵角色模型202407051607 这次HumbleBundle捆绑包是UE虚幻军事题材的,内容非常多。 有军事基地、赛博朋克街区、灌木丛景观环境等 HB捆绑包虚幻…

【Python】基于KMeans的航空公司客户数据聚类分析

💐大家好!我是码银~,欢迎关注💐: CSDN:码银 公众号:码银学编程 实验目的和要求 会用Python创建Kmeans聚类分析模型使用KMeans模型对航空公司客户价值进行聚类分析会对聚类结果进行分析评价 实…

springboot 社区垃圾回收处理小程序-计算机毕业设计源码71905

摘要 在数字化高速发展的今天,随着Spring Boot等轻量级框架的广泛应用,各种小程序、微服务如雨后春笋般涌现,极大地丰富了我们的软件生态系统。然而,伴随着这些应用的迅速增加,垃圾回收处理成为了一个不可忽视的问题。…

Mybatis原生使用

一、MyBatis初次使用 2.1 环境搭建步骤 MyBatis 的 API : https://mybatis.org/mybatis-3/zh/getting-started.html 1.引入依赖包 2.准备核心配置件 db.properties drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://123.57.206.19:3306/demo?useUnicodetrue&am…

步进电机改伺服电机

步进电机: 42:轴径5mm 57:轴径8mm 86:轴径14mm 【86CME120闭环】// 12牛米 伺服电机: 40: 60: 80: 86: ECMA——C 1 0910 R S 4.25A 轴径…

26.5 Django模板层

1. 模版介绍 在Django中, 模板(Templates)主要用于动态地生成HTML页面. 当需要基于某些数据(如用户信息, 数据库查询结果等)来动态地渲染HTML页面时, 就会使用到模板.以下是模板在Django中使用的几个关键场景: * 1. 动态内容生成: 当需要根据数据库中的数据或其他动态数据来生…

Hook 实现 Windows 系统热键屏蔽(二)

目录 前言 一、介绍用户账户控制(UAC) 1.1 什么是 UAC ? 2.2 UAC 运行机制的概述 2.3 分析 UAC 提权参数 二、 NdrAsyncServerCall 函数的分析 2.1 函数声明的解析 2.2 对 Winlogon 的逆向 2.3 对 rpcrt4 的静态分析 2.4 对 rpcrt4…