news 2026/4/16 19:27:10

图片坐标查看器

作者头像

张小明

前端开发工程师

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/4/16 11:11:17

21、正则表达式完全指南

正则表达式完全指南 正则表达式基础 正则表达式是用于匹配文本模式的强大工具。它由普通字符和元字符组成。普通字符就是它们本身,而元字符则用于指定更复杂的匹配规则。正则表达式的元字符包括: ^ $ . [ ] { } - ? * + ( ) | \ 。除了这些元字符,其他字符都被视为普通…

作者头像 李华
网站建设 2026/4/16 11:15:29

深入浅出 Ajax:从原理到实战,打造高可靠的前端请求方案

在前端开发中&#xff0c;Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是实现 “无刷新交互” 的核心技术&#xff0c;尤其在后台管理系统、电商平台等场景中&#xff0c;Ajax 几乎是前端与后端通信的标配。尽管如今 Fetch API、Axios 等工具层出不穷&#xf…

作者头像 李华
网站建设 2026/4/16 13:00:30

语言模型中的因果推理能力增强方法

语言模型中的因果推理能力增强方法关键词&#xff1a;语言模型、因果推理能力、增强方法、算法原理、应用场景摘要&#xff1a;本文围绕语言模型中的因果推理能力增强方法展开深入探讨。首先介绍了研究背景&#xff0c;包括目的范围、预期读者等内容。接着阐述了因果推理与语言…

作者头像 李华
网站建设 2026/4/16 16:12:41

vue和springboot框架开发的企业合同信息管理系统_jwz8674j

文章目录具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 同行可拿货,招校园代理 vuespringboot_jwz8674j 框架开发的企业合同信息管理系…

作者头像 李华
网站建设 2026/4/16 18:17:49

SpringBoot+Vue 大学生考勤系统管理平台源码【适合毕设/课设/学习】Java+MySQL

摘要 随着高校教育信息化建设的不断深入&#xff0c;传统的考勤管理方式逐渐暴露出效率低下、数据易丢失、统计困难等问题。大学生考勤系统管理平台通过数字化手段&#xff0c;实现了考勤数据的实时记录、自动化统计和可视化分析&#xff0c;有效提升了教学管理的效率和准确性。…

作者头像 李华
网站建设 2026/4/16 12:51:05

[特殊字符] 高校写作新困境:课程论文如何兼顾效率与学术深度?

&#x1f4da; 高校写作新困境&#xff1a;课程论文如何兼顾效率与学术深度&#xff1f; 对于高校学生而言&#xff0c;课程论文不仅是学业考核的重要指标&#xff0c;更是学术思维与研究能力培养的关键载体。但现实写作场景中&#xff0c;痛点却贯穿全程&#xff1a;选题阶段…

作者头像 李华