news 2026/1/16 9:32:29

图片坐标查看器

作者头像

张小明

前端开发工程师

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/1/15 2:48:49

基于SpringBoot+Vue的web项目申报系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 随着信息技术的快速发展&#xff0c;传统的手工申报管理模式已无法满足现代企事业单位对高效、便捷、透明化管理的需求。项目申报管理系统作为一种信息化工具&#xff0c;能够有效解决申报流程繁琐、数据管理混乱、审批效率低下等问题。该系统通过数字化手段实现项目申报、…

作者头像 李华
网站建设 2026/1/15 9:09:52

当问卷告别 “凭经验设计”:宏智树 AI 重构科研测量的精准逻辑

当问卷告别 “凭经验设计”&#xff1a;宏智树 AI 重构科研测量的精准逻辑 你是否有过这样的困惑&#xff1f;花费数月设计的问卷&#xff0c;回收数据后却发现变量相关性微弱&#xff0c;研究假设无法验证&#xff1b;严格按照模板制作的量表&#xff0c;在特定样本群体中信度…

作者头像 李华
网站建设 2026/1/14 22:49:16

【限时揭秘】工业质检Agent精度提升的3个非公开训练技巧

第一章&#xff1a;工业质检Agent精度提升的核心挑战在现代智能制造体系中&#xff0c;工业质检Agent作为自动化质量控制的关键组件&#xff0c;其检测精度直接影响产品良率与生产效率。然而&#xff0c;在实际部署过程中&#xff0c;精度提升面临多重技术与工程挑战。数据质量…

作者头像 李华
网站建设 2026/1/13 19:09:32

基于SpringBoot的墙绘产品展示交易平台的设计与实现(11516)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华