news 2026/6/10 2:06:22

图片坐标查看器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图片坐标查看器
importtkinterastkfromtkinterimportfiledialogimportcustomtkinterasctkfromPILimportImage,ImageTkimportplatform# <span style="color: red;">【关键配置】解除 Pillow 的大图像素限制</span>Image.MAX_IMAGE_PIXELS=Nonectk.set_appearance_mode("Dark")classViewportImageViewer(ctk.CTk):def__init__(self):super().__init__()self.title("无限大图查看器 (视口渲染 + 坐标显示)")self.geometry("1100x750")# --- 核心数据 ---self.src_image=None# 原图对象 (Lazy Load)self.current_scale=1.0# 缩放倍率self.img_pos_x=0# 图片在画布上的左上角 Xself.img_pos_y=0# 图片在画布上的左上角 Y# 交互状态self.last_mouse_x=0self.last_mouse_y=0self.render_job=None# 防抖任务定时器# --- UI 布局 ---self.grid_columnconfigure(1,weight=1)self.grid_rowconfigure(0,weight=1)# 1. 左侧控制栏self.sidebar=ctk.CTkFrame(self,width=200,corner_radius=0)self.sidebar.grid(row=0,column=0,sticky="nsew")ctk.CTkLabel(self.sidebar,text="Ultra Viewer",font=("Arial",20,"bold")).pack(pady=30)ctk.CTkButton(self.sidebar,text="📂 打开超大图",command=self.open_image).pack(pady=10,padx=20)self.info_label=ctk.CTkLabel(self.sidebar,text="等待加载...",text_color="gray")self.info_label.pack(pady=10)# --- 新增:坐标显示区域 ---self.coord_card=ctk.CTkFrame(self.sidebar,fg_color="gray20",corner_radius=10)self.coord_card.pack(pady=30,padx=20,fill="x")ctk.CTkLabel(self.coord_card,text="X / Y 坐标",font=("Arial",12)).pack(pady=5)self.lbl_coord=ctk.CTkLabel(self.coord_card,text="- , -",font=("Arial",18,"bold"),text_color="#3B8ED0")self.lbl_coord.pack(pady=(0,15))# 调试信息 (可选)self.debug_label=ctk.CTkLabel(self.sidebar,text="",font=("Consolas",10),text_color="gray50")self.debug_label.pack(side="bottom",pady=20,anchor="w",padx=10)# 2. 右侧画布self.canvas=tk.Canvas(self,bg="#2b2b2b",highlightthickness=0)self.canvas.grid(row=0,column=1,sticky="nsew")# --- 事件绑定 ---# 拖拽相关self.canvas.bind("<ButtonPress-1>",self.on_mouse_down)self.canvas.bind("<B1-Motion>",self.on_mouse_drag)# 滚轮缩放ifplatform.system()=="Linux":self.canvas.bind("<Button-4>",lambdae:self.on_zoom(e,1.1))self.canvas.bind("<Button-5>",lambdae:self.on_zoom(e,0.9))else:self.canvas.bind("<MouseWheel>",self.on_wheel)# 窗口重绘self.canvas.bind("<Configure>",lambdae:self.request_render())# --- 新增:鼠标移动监听 (用于更新坐标) ---self.canvas.bind("<Motion>",self.show_coords)defopen_image(self):file_path=filedialog.askopenfilename()ifnotfile_path:returntry:# Lazy Load: 只读头信息,不读像素self.src_image=Image.open(file_path)# 初始化:适应屏幕win_w=self.canvas.winfo_width()win_h=self.canvas.winfo_height()img_w,img_h=self.src_image.size self.current_scale=min(win_w/img_w,win_h/img_h)*0.9# 居中计算disp_w=img_w*self.current_scale disp_h=img_h*self.current_scale self.img_pos_x=(win_w-disp_w)/2self.img_pos_y=(win_h-disp_h)/2self.info_label.configure(text=f"尺寸:{img_w}x{img_h}\n格式:{self.src_image.format}")self.request_render()exceptExceptionase:print(f"Error:{e}")defshow_coords(self,event):"""新增:实时计算鼠标下的真实图片坐标"""ifnotself.src_image:return# 1. 计算相对于图片左上角的屏幕像素距离# 公式: 鼠标屏幕位置 - 图片左上角屏幕位置screen_rel_x=event.x-self.img_pos_x screen_rel_y=event.y-self.img_pos_y# 2. 换算回原图尺寸# 公式: 屏幕距离 / 缩放倍率real_x=int(screen_rel_x/self.current_scale)real_y=int(screen_rel_y/self.current_scale)# 3. 边界检查 (防止显示负数或超出图片范围)if0<=real_x<self.src_image.widthand0<=real_y<self.src_image.height:self.lbl_coord.configure(text=f"{real_x},{real_y}",text_color="#3B8ED0")else:self.lbl_coord.configure(text="越界",text_color="red")defon_mouse_down(self,event):self.last_mouse_x=event.x self.last_mouse_y=event.ydefon_mouse_drag(self,event):ifnotself.src_image:returndx=event.x-self.last_mouse_x dy=event.y-self.last_mouse_y self.img_pos_x+=dx self.img_pos_y+=dy self.last_mouse_x=event.x self.last_mouse_y=event.y# 拖拽时只移动画布元素,不重绘图片内容 (高性能)self.canvas.move("img_tag",dx,dy)# 拖拽时也要更新坐标self.show_coords(event)self.debounce_render()defon_wheel(self,event):factor=1.1ifevent.delta>0else0.9self.on_zoom(event,factor)defon_zoom(self,event,factor):ifnotself.src_image:returnmouse_x=event.x mouse_y=event.y# 记录鼠标在图片内部的相对比例 (0.0~1.0)rel_x=(mouse_x-self.img_pos_x)/(self.src_image.width*self.current_scale)rel_y=(mouse_y-self.img_pos_y)/(self.src_image.height*self.current_scale)# 更新缩放self.current_scale*=factor# 修正位置,保持鼠标下的点不动new_w=self.src_image.width*self.current_scale new_h=self.src_image.height*self.current_scale self.img_pos_x=mouse_x-(rel_x*new_w)self.img_pos_y=mouse_y-(rel_y*new_h)self.request_render()# 缩放后立即更新坐标显示self.show_coords(event)defdebounce_render(self):ifself.render_job:self.after_cancel(self.render_job)self.render_job=self.after(50,self.request_render)defrequest_render(self):ifnotself.src_image:returnwin_w=self.canvas.winfo_width()win_h=self.canvas.winfo_height()# --- 视口裁切算法 ---# 计算可视区域对应的原图坐标范围left=-self.img_pos_x/self.current_scale top=-self.img_pos_y/self.current_scale right=(win_w-self.img_pos_x)/self.current_scale bottom=(win_h-self.img_pos_y)/self.current_scale crop_left=max(0,int(left))crop_top=max(0,int(top))crop_right=min(self.src_image.width,int(right)+1)crop_bottom=min(self.src_image.height,int(bottom)+1)ifcrop_right<=crop_leftorcrop_bottom<=crop_top:self.canvas.delete("img_tag")returntry:# 1. 从硬盘裁切 (Crop)tile=self.src_image.crop((crop_left,crop_top,crop_right,crop_bottom))# 2. 缩放到屏幕显示尺寸 (Resize)display_w=int((crop_right-crop_left)*self.current_scale)display_h=int((crop_bottom-crop_top)*self.current_scale)ifdisplay_w>0anddisplay_h>0:# 使用 Nearest 模式以获得最快速度 (大图浏览通常不需要插值平滑)tile=tile.resize((display_w,display_h),Image.Resampling.NEAREST)self.tk_image=ImageTk.PhotoImage(tile)# 3. 放置到画布canvas_x=self.img_pos_x+crop_left*self.current_scale canvas_y=self.img_pos_y+crop_top*self.current_scale self.canvas.delete("img_tag")self.canvas.create_image(canvas_x,canvas_y,anchor="nw",image=self.tk_image,tags="img_tag")self.debug_label.configure(text=f"View:{crop_left}:{crop_top}->{crop_right}:{crop_bottom}")exceptExceptionase:print(f"Render Error:{e}")if__name__=="__main__":app=ViewportImageViewer()app.mainloop()

只要鼠标放在图片区域内就能显示坐标,图片支持无限制放大缩小,移动位置,流畅不卡顿







版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 21:37:58

20、数据处理:压缩、同步与正则匹配的实用指南

数据处理:压缩、同步与正则匹配的实用指南 在数据处理和存储过程中,文件的压缩、同步以及文本的搜索匹配是常见的操作。本文将详细介绍几种实用的工具和技术,包括 tar 、 zip 、 rsync 以及正则表达式相关的 grep 命令,帮助你更好地管理和操作数据。 tar 命令:…

作者头像 李华
网站建设 2026/6/9 15:47:45

基于SpringBoot+Vue的考试系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 随着信息技术的快速发展&#xff0c;传统考试管理模式已无法满足现代教育的高效化、智能化需求。考试管理系统的数字化升级成为教育信息化建设的重要组成部分。传统考试流程依赖纸质试卷和人工阅卷&#xff0c;效率低下且易出错&#xff0c;尤其在远程教育和在线学习普及的…

作者头像 李华
网站建设 2026/6/9 21:27:42

“全流程赋能 + 真实素材 + AI 硬核实力

一、品牌定位&#xff1a;不止于写作辅助&#xff0c;更是学术创新的智能伙伴 宏智树 AI&#xff08;官网&#xff1a;www.hzsxueshu.com&#xff09;是一款深度融合人工智能技术与学术写作逻辑的全流程辅助工具&#xff0c;打破传统写作工具 “单一功能、表层赋能” 的局限&a…

作者头像 李华
网站建设 2026/6/9 23:38:35

⚠️ 毕业季避坑!AI 写论文哪个软件最好?5 款真实工具实测揭秘

“AI 写论文软件选不对&#xff0c;不仅浪费时间&#xff0c;还可能踩学术诚信红线&#xff01;”—— 每年毕业季&#xff0c;都有无数学生因选错工具导致论文重写、答辩翻车。市面上 AI 写作工具五花八门&#xff0c;到底哪款能真正帮到毕业生&#xff1f;我们针对 5 款主流真…

作者头像 李华
网站建设 2026/6/9 22:43:30

探索前沿:LabVIEW、Matlab与基因检测仿真系统设计

基于labview和matlab的数字语音信号处理系统、基于简化逆滤波的基因检测仿真系统设计。在科技飞速发展的今天&#xff0c;数字信号处理和基因检测领域不断取得新突破。今天就和大家聊聊基于LabVIEW和Matlab的数字语音信号处理系统&#xff0c;以及基于简化逆滤波的基因检测仿真…

作者头像 李华
网站建设 2026/6/9 22:47:37

Typora代码块痛点全攻略

Typora代码块痛点破解方案技术文章大纲痛点分析&#xff1a;Typora代码块的常见问题语法高亮支持有限&#xff0c;部分语言无法正确渲染 代码块复制时可能携带行号或格式混乱 大型代码块在导出为PDF时出现换行或分页问题 实时预览模式下代码块编辑体验不流畅解决方案一&#xf…

作者头像 李华