8.20更新了一下,一个指定图片上物体尺寸生成pdf来打印的小工具,提供源码

查看 99|回复 10
作者:858983646   
使用场景:比如身份证随手一拍,用这个可以打印出和原件一样大
1.使用方法:打开软件,选择图片,然后图片上选择两个点,输入想
要两个点之间的距离,单位mm,点计算结果宽度(这个结果是图片应
该的宽度),然后输出pdf即可。pdf是a4大小
2.也可以手动直接输入最终的图片宽度来打印
3.用了低版本Python编译,win7 32位应该可以运行了,没测试
4.更新了1.6版本, 加了个放大镜方便选择图片里的点
链接:https://pan.baidu.com/s/1wQ_w4U3JtX-HpZC3z_ELpA 提取码:5osy
界面就只有这能力了,都是问的ai,图片显示不能放大缩小,是把原图缩放了显示进去的,只能说能用


2_proc.jpg (65.57 KB, 下载次数: 0)
下载附件
2024-8-20 22:02 上传



1_proc.jpg (58.98 KB, 下载次数: 0)
下载附件
2024-8-20 22:02 上传

[Python] 纯文本查看 复制代码# 导入必要的库
import cv2
import numpy as np
from tkinter import Tk, Button, Label, Entry, filedialog, Canvas, messagebox
from PIL import Image, ImageTk
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
# 定义ImageSelector类
class ImageSelector:
    def __init__(self, root):
        # 初始化根窗口和类属性
        self.root = root
        self.root.title('图像选择器与PDF创建器')
        self.original_image = None
        self.photo_image = None
        self.points = []
        self.result = None
        self.original_image_path = None
        self.scale = 1.0  # 初始化缩放比例
        self.first_point = None  # 新增属性,保存第一个点的坐标
        self.line1 = None  # 新增属性,保存实时连接线的对象
        self.zoom_canvas = None  # 新增属性,保存用于显示放大图像的画板
        # 创建垂直布局的框架
        self.frame = Canvas(self.root, width=200, height=750)
        self.frame.pack(side='right', fill='y')
        # 在框架内创建按钮、标签等
        self.load_image_button = self.create_button('加载图片', self.load_image)
        self.canvas = self.create_canvas()
        self.clear_button = self.create_button('清除标记点', self.clear_points)
        self.entry_label = self.create_label('输入两点间距离(mm):')
        self.entry = Entry(self.frame, width=20)
        self.entry.pack(side='top', fill='x')
        self.result_button = self.create_button('计算宽度', self.calculate_result)
        self.result_label = Label(self.frame, text="计算出的图片宽度(mm): ", font=('Arial', 12))
        self.result_label.pack(side='top', padx=10, pady=5)
        self.create_pdf_button = self.create_button('创建PDF', self.create_pdf)
        self.result_entry = Entry(self.frame, width=20)
        self.result_entry.pack(side='top', fill='x')
        self.result_entry.bind("", lambda event: app.update_result_from_input(app.result_entry.get()))
        self.manual_update_button = self.create_button('手动输入图片宽度(mm)', lambda: app.update_result_from_input(app.result_entry.get()))
        # 创建用于显示放大图像的小画板,并将其放置在框架的下方
        self.zoom_canvas = Canvas(self.frame, width=200, height=200, bg='white')  # 根据需要调整尺寸
        self.zoom_canvas.pack(side='top')
    # 创建按钮的方法
    def create_button(self, text, command):
        button = Button(self.frame, text=text, command=command)
        button.pack(fill='x')
        return button
    # 创建画布的方法
    def create_canvas(self):
        # 创建主画板
        canvas = Canvas(self.root, width=1000, height=750)
        canvas.pack(side='left', fill='both', expand=True)
        canvas.bind("[B]", self.on_canvas_click)
        canvas.bind("", self.on_canvas_motion)
        
        # 创建用于显示放大图像的画板
        #self.zoom_canvas = Canvas(self.root, width=100, height=100, bg='white')
        #self.zoom_canvas.pack(side='right', padx=10, pady=10)
        
        return canvas
    # 创建标签的方法
    def create_label(self, text):
        label = Label(self.frame, text=text)
        label.pack(side='top', fill='x')
        return label
    # 加载图像的方法
    def load_image(self):
        file_path = filedialog.askopenfilename(
            title = "选择图片",
            filetypes = (("JPG files", "*.jpg"), ("PNG files", "*.png"), ("All files", "*.*"))
    )
        if file_path:
            self.original_image = self.imread_with_chinese_chars(file_path)
            if self.original_image is None:
                messagebox.showerror("Error", "图片未找到,请检查路径。")
                return
            self.original_image_path = file_path
            canvas_size = (self.canvas.winfo_width(), self.canvas.winfo_height())
            self.photo_image, self.scale = self.resize_image(self.original_image, canvas_size)
            self.canvas.create_image(0, 0, image=self.photo_image, anchor='nw')
            self.canvas.image = self.photo_image
    # 读取中文路径图片的方法
    def imread_with_chinese_chars(self, file_path):
        image = Image.open(file_path)
        return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
    # 调整图像大小的方法,保持比例
    def resize_image(self, image, canvas_size):
        (h, w) = image.shape[:2]
        (cw, ch) = canvas_size
        scale = min(cw/w, ch/h)
        new_size = (int(w * scale), int(h * scale))
        new_image = cv2.resize(image, new_size, interpolation=cv2.INTER_AREA)
        canvas_image = Image.fromarray(cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB))
        return ImageTk.PhotoImage(canvas_image), scale
    # 画布点击事件的回调方法
    def on_canvas_click(self, event):
    #self.update_zoom_canvas(event.x, event.y)
        if self.first_point is None:
            # 第一次点击,记录第一个点的位置
            self.first_point = (event.x, event.y)
            self.line1 = self.canvas.create_line(
                self.first_point[0], self.first_point[1], event.x, event.y, fill='red', width=1, tags='line')
        else:
            # 第二次点击,完成线的绘制,记录第二个点,并重置first_point和points列表
            self.canvas.coords(self.line1, self.first_point[0], self.first_point[1], event.x, event.y)
            self.points = [self.first_point, (event.x, event.y)]  # 更新points列表
            self.first_point = None  # 重置first_point
            self.line1 = None  # 重置线对象
        self.update_zoom_canvas(event.x, event.y)
    # 鼠标移动事件的回调方法
    def on_canvas_motion(self, event):
        if self.first_point:
            if self.line1:
                self.canvas.coords(self.line1, self.first_point[0], self.first_point[1], event.x, event.y)
        # 当鼠标移动时,更新副画板的图像
        if self.original_image is not None:  # 确保已经加载了图像
            self.update_zoom_canvas(event.x, event.y)
    def update_zoom_canvas(self, x, y):
        # 计算放大区域在原始图像中的坐标
        zoom_x = int(x / self.scale)  # 根据缩放比例计算原始图像的坐标
        zoom_y = int(y / self.scale)
        zoom_width = 50  # 定义放大区域的宽度为20像素
        zoom_height = 50  # 定义放大区域的高度为20像素
         # 确保放大区域不超出原始图像边界
        left = max(0, zoom_x - zoom_width // 2)
        top = max(0, zoom_y - zoom_height // 2)
        right = min(zoom_x + zoom_width // 2,   self.original_image.shape[1])
        bottom = min(zoom_y + zoom_height // 2, self.original_image.shape[0])
        # 裁剪放大区域
        zoom_area = self.original_image[top:bottom, left:right]
        # 调整裁剪区域的大小以适应zoom_canvas
        zoom_area_resized = cv2.resize(zoom_area, (self.zoom_canvas.winfo_width(), self.zoom_canvas.winfo_height()), interpolation=cv2.INTER_AREA)
        # 转换颜色空间并创建PhotoImage对象
        canvas_image = Image.fromarray(cv2.cvtColor(zoom_area_resized, cv2.COLOR_BGR2RGB))
        photo_image = ImageTk.PhotoImage(canvas_image)
        # 删除zoom_canvas上的旧图像
        self.zoom_canvas.delete("all")  # 使用"all"来删除画布上的所有元素
        # 在zoom_canvas上显示新的放大图像
        self.zoom_canvas.create_image(0, 0, image=photo_image, anchor='nw')
        self.zoom_canvas.image = photo_image
        # 绘制小红叉
        cross_size = 5  # 定义小红叉的臂长
        cross_thickness = 2  # 定义小红叉的线宽
        zoom_center_x = self.zoom_canvas.winfo_width() // 2
        zoom_center_y = self.zoom_canvas.winfo_height() // 2
        self.zoom_canvas.create_line(zoom_center_x - cross_size, zoom_center_y, zoom_center_x + cross_size, zoom_center_y, fill='red', width=cross_thickness)
        self.zoom_canvas.create_line(zoom_center_x, zoom_center_y - cross_size, zoom_center_x, zoom_center_y + cross_size, fill='red', width=cross_thickness)
    # 清除画布上点的方法
    def clear_points(self):
        self.canvas.delete('point')
        self.canvas.delete('line')
        self.points = []
        self.first_point = None
        if self.line1:
            self.canvas.delete(self.line1)
            self.line1 = None
    # 计算两点间距离的方法
    def calculate_distance(self):
        if len(self.points) >= 2:
            point1, point2 = self.points[:2]
            distance = np.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
            messagebox.showinfo("Distance", f"两点间距离: {distance}px")
        else:
            messagebox.showerror("Error", "请至少选择两个点。")
    # 计算结果的方法
    def calculate_result(self):
        try:
            input_value = float(self.entry.get())
            if len(self.points) >= 2 and self.scale != 1.0:
                point1, point2 = self.points[:2]
                distance_pixels = np.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
                self.result = (input_value / distance_pixels) * self.original_image.shape[1] * self.scale
                self.result_label.config(text=f"图片宽度: {self.result:.2f}mm")
            else:
                messagebox.showerror("Error", "请至少选择两个点,并且图像已加载。")
        except ValueError:
            messagebox.showerror("Error", "输入无效,请输入一个数值。")
    # 创建PDF文件的方法
    def create_pdf(self):
        try:
            if self.result is None or self.result

图像, 图片

858983646
OP
  

更新了下新版本,小圆点改成了连线,好分辨一点,然后改了下布局
可以手动直接输入最终的图片宽度了
用了低版本Python编译,win7 32位应该可以运行了


Screenshot_2024-08-20-13-59-19-719_com.realvnc.viewer.android-edit.jpg (26.87 KB, 下载次数: 0)
下载附件
2024-8-20 14:01 上传

[Python] 纯文本查看 复制代码# 导入必要的库
import cv2
import numpy as np
from tkinter import Tk, Button, Label, Entry, filedialog, Canvas, messagebox
from PIL import Image, ImageTk
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
# 定义ImageSelector类
class ImageSelector:
    def __init__(self, root):
        # 初始化根窗口和类属性
        self.root = root
        self.root.title('图像选择器与PDF创建器')
        self.original_image = None
        self.photo_image = None
        self.points = []
        self.result = None
        self.original_image_path = None
        self.scale = 1.0  # 初始化缩放比例
        self.first_point = None  # 新增属性,保存第一个点的坐标
        self.line1 = None  # 新增属性,保存实时连接线的对象
        # 创建垂直布局的框架
        self.frame = Canvas(self.root, width=200, height=750)
        self.frame.pack(side='right', fill='y')
        # 在框架内创建按钮、标签等
        self.load_image_button = self.create_button('加载图片', self.load_image)
        self.canvas = self.create_canvas()
        self.clear_button = self.create_button('清除标记点', self.clear_points)
        self.entry_label = self.create_label('输入两点间距离单位mm:')
        self.entry = Entry(self.frame, width=20)
        self.entry.pack(side='top', fill='x')
        self.result_button = self.create_button('计算宽度', self.calculate_result)
        self.result_label = Label(self.frame, text="图片宽度mm: ", font=('Arial', 12))
        self.result_label.pack(side='top', padx=10, pady=5)
        self.create_pdf_button = self.create_button('创建PDF', self.create_pdf)
        self.result_entry = Entry(self.frame, width=20)
        self.result_entry.pack(side='top', fill='x')
        self.result_entry.bind("", lambda event: app.update_result_from_input(app.result_entry.get()))
        self.manual_update_button = self.create_button('手动输入图片宽度', lambda: app.update_result_from_input(app.result_entry.get()))
    # 创建按钮的方法
    def create_button(self, text, command):
        button = Button(self.frame, text=text, command=command)
        button.pack(fill='x')
        return button
    # 创建画布的方法
    def create_canvas(self):
        canvas = Canvas(self.root, width=1000, height=750)
        canvas.pack(side='left', fill='both', expand=True)
        canvas.bind("[B]", self.on_canvas_click)
        canvas.bind("", self.on_canvas_motion)  # 绑定鼠标移动事件
        return canvas
    # 创建标签的方法
    def create_label(self, text):
        label = Label(self.frame, text=text)
        label.pack(side='top', fill='x')
        return label
    # 加载图像的方法
    def load_image(self):
        file_path = filedialog.askopenfilename(
            title = "选择图片",
            filetypes = (("JPG files", "*.jpg"), ("PNG files", "*.png"), ("All files", "*.*"))
    )
        if file_path:
            self.original_image = self.imread_with_chinese_chars(file_path)
            if self.original_image is None:
                messagebox.showerror("Error", "图片未找到,请检查路径。")
                return
            self.original_image_path = file_path
            canvas_size = (self.canvas.winfo_width(), self.canvas.winfo_height())
            self.photo_image, self.scale = self.resize_image(self.original_image, canvas_size)
            self.canvas.create_image(0, 0, image=self.photo_image, anchor='nw')
            self.canvas.image = self.photo_image
    # 读取中文路径图片的方法
    def imread_with_chinese_chars(self, file_path):
        image = Image.open(file_path)
        return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
    # 调整图像大小的方法,保持比例
    def resize_image(self, image, canvas_size):
        (h, w) = image.shape[:2]
        (cw, ch) = canvas_size
        scale = min(cw/w, ch/h)
        new_size = (int(w * scale), int(h * scale))
        new_image = cv2.resize(image, new_size, interpolation=cv2.INTER_AREA)
        canvas_image = Image.fromarray(cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB))
        return ImageTk.PhotoImage(canvas_image), scale
    # 画布点击事件的回调方法
    def on_canvas_click(self, event):
        if self.first_point is None:
            # 第一次点击,记录第一个点的位置
            self.first_point = (event.x, event.y)
            self.line1 = self.canvas.create_line(
                self.first_point[0], self.first_point[1], event.x, event.y, fill='red', width=1, tags='line')
        else:
            # 第二次点击,完成线的绘制,记录第二个点,并重置first_point和points列表
            self.canvas.coords(self.line1, self.first_point[0], self.first_point[1], event.x, event.y)
            self.points = [self.first_point, (event.x, event.y)]  # 更新points列表
            self.first_point = None  # 重置first_point
            self.line1 = None  # 重置线对象
    # 鼠标移动事件的回调方法
    def on_canvas_motion(self, event):
        if self.first_point:
            if self.line1:
                self.canvas.coords(self.line1, self.first_point[0], self.first_point[1], event.x, event.y)
    # 清除画布上点的方法
    def clear_points(self):
        self.canvas.delete('point')
        self.canvas.delete('line')
        self.points = []
        self.first_point = None
        if self.line1:
            self.canvas.delete(self.line1)
            self.line1 = None
    # 计算两点间距离的方法
    def calculate_distance(self):
        if len(self.points) >= 2:
            point1, point2 = self.points[:2]
            distance = np.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
            messagebox.showinfo("Distance", f"两点间距离: {distance}px")
        else:
            messagebox.showerror("Error", "请至少选择两个点。")
    # 计算结果的方法
    def calculate_result(self):
        try:
            input_value = float(self.entry.get())
            if len(self.points) >= 2 and self.scale != 1.0:
                point1, point2 = self.points[:2]
                distance_pixels = np.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
                self.result = (input_value / distance_pixels) * self.original_image.shape[1] * self.scale
                self.result_label.config(text=f"图片宽度: {self.result:.2f}mm")
            else:
                messagebox.showerror("Error", "请至少选择两个点,并且图像已加载。")
        except ValueError:
            messagebox.showerror("Error", "输入无效,请输入一个数值。")
    # 创建PDF文件的方法
    def create_pdf(self):
        try:
            if self.result is None or self.result
858983646
OP
  


yueyegufeng 发表于 2024-8-16 19:37
没看明白,这是啥功能?

比如我拍张照片,里面有一个硬币,我要把照片打印出来,让硬币直径是2cm,这种场景
饮食协会   

为何取消分享  ????这正是多年苦苦寻找的东西啊
饮食协会   

哎  找寻了二十年  就手慢了一秒钟
858983646
OP
  


饮食协会 发表于 2024-8-16 12:54
为何取消分享  ????这正是多年苦苦寻找的东西啊

更新了下,之前比例错了
858983646
OP
  


饮食协会 发表于 2024-8-16 12:56
哎  找寻了二十年  就手慢了一秒钟

更新了下,之前比例错了
858983646
OP
  


饮食协会 发表于 2024-8-16 12:56
哎  找寻了二十年  就手慢了一秒钟

又改了下,应该可以正常用了
风见野   

太感谢了,确实是自己一直想要做但没做成的东西。之前都是自己硬试出来
yueyegufeng   

没看明白,这是啥功能?
您需要登录后才可以回帖 登录 | 立即注册

返回顶部