当前位置: 首页 > news >正文

python纯终端实现图片查看器(全彩)(windows)

很多人作为命令行爱好者,无法在终端内直接查看图片是无法忍受的,

那就写一个!

先直接上代码

import os
import sys
from PIL import Image
import numpy as np
import colorama
import msvcrt  # Windows专用

# 初始化colorama
colorama.init()

# 更丰富的字符梯度,用于更好的放大效果

chars = [" ", "░", "▒", "▓", "█", "▀", "▄", "▌", "▐", "■", "◢", "◣", "◤", "◥", "◧", "◨", "◩", "◪", "◫"]

def clear_screen():
    """清屏"""
    os.system('cls' if os.name == 'nt' else 'clear')

def image_to_ansiart(image_path, width=80, scale=1.0):
    """将图片转换为ANSI彩色字符画,支持平滑缩放"""
    try:
        img = Image.open(image_path)
    except Exception as e:
        return f"[无法加载图片: {str(e)}]"
    
    # 应用缩放因子
    width = int(width * scale)
    aspect_ratio = img.height / img.width
    height = int(width * aspect_ratio * 0.45)  # 调整高宽比以获得更好显示效果
    
    # 确保最小尺寸
    width = max(10, width)  # 最小宽度设为10
    height = max(5, height)  # 最小高度设为5
    
    # 使用高质量缩放
    img = img.resize((width, height), Image.Resampling.LANCZOS)
    img = img.convert("RGB")
    pixels = np.array(img)
    
    ansi_lines = []
    for row in pixels:
        line = []
        for pixel in row:
            r, g, b = pixel
            brightness = 0.299 * r + 0.587 * g + 0.114 * b
            
            # 选择字符,使用更精细的亮度分级
            char_idx = int(brightness / 255 * (len(chars) - 1))
            char = chars[char_idx]
            
            # 使用24位真彩色
            line.append(f"\x1b[38;2;{r};{g};{b}m{char}")
        ansi_lines.append("".join(line) + "\x1b[0m")
    
    return "\n".join(ansi_lines)

def get_terminal_size():
    """获取终端大小"""
    try:
        from shutil import get_terminal_size as gts
        return gts().columns, gts().lines
    except:
        return 80, 24  # 默认值

def get_image_list(start_image=None):
    """获取当前目录图片列表,并定位到指定图片"""
    images = sorted([f for f in os.listdir() 
                   if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp'))])
    
    if not images:
        print("当前目录没有图片文件(支持.png/.jpg/.jpeg/.bmp/.gif/.webp)")
        return None, -1
    
    # 如果指定了初始图片,尝试定位
    idx = 0
    if start_image:
        start_image = os.path.basename(start_image)  # 只取文件名部分
        try:
            idx = images.index(start_image)
        except ValueError:
            # 如果文件不在当前目录,添加到列表并设为当前图片
            if os.path.exists(start_image):
                images.append(start_image)
                images.sort()
                idx = images.index(start_image)
            else:
                print(f"警告: 指定的图片文件 {start_image} 不存在")
    
    return images, idx

def main():
    # 处理命令行参数
    start_image = sys.argv[1] if len(sys.argv) > 1 else None
    
    # 获取图片列表和初始索引
    images, idx = get_image_list(start_image)
    if not images:
        return
    
    scale = 1.0
    base_width = min(80, get_terminal_size()[0] - 10)  # 根据终端宽度调整
    
    while True:
        clear_screen()
        
        # 显示图片信息和控制说明
        print(f"图片查看器: {images[idx]} ({idx+1}/{len(images)}) 缩放: {scale:.1f}x")
        print("← →:切换图片 | + -:缩放(0.2x-5.0x) | Home/End:首图/末图 | Q:退出")
        print("-" * min(80, get_terminal_size()[0]))
        
        try:
            # 显示图片
            art = image_to_ansiart(images[idx], base_width, scale)
            print(art)
        except Exception as e:
            print(f"渲染错误: {str(e)}")
        
        # 获取按键
        key = msvcrt.getch()
        try:
            key = key.decode('utf-8').lower()
        except:
            key = str(key)
        
        # 处理按键
        if key == 'q':
            break
        elif key == '+' and scale < 5.0:
            scale = min(5.0, scale + 0.1)  # 更精细的缩放控制
        elif key == '-' and scale > 0.2:
            scale = max(0.2, scale - 0.1)
        elif key == '\x00' or key == '\xe0':  # 功能键前缀
            next_key = msvcrt.getch()
            if next_key == b'M' or next_key == b'P':  # 右箭头或下箭头
                idx = (idx + 1) % len(images)
                scale = 1.0
            elif next_key == b'K' or next_key == b'H':  # 左箭头或上箭头
                idx = (idx - 1) % len(images)
                scale = 1.0
            elif next_key == b'G':  # Home键
                idx = 0
                scale = 1.0
            elif next_key == b'O':  # End键
                idx = len(images) - 1
                scale = 1.0
        elif key == '\r':  # 回车键重置缩放
            scale = 1.0
        elif key == 'f':  # 切换全屏/正常模式
            base_width = get_terminal_size()[0] - 10 if base_width < 100 else 80

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        pass
    except Exception as e:
        print(f"程序出错: {str(e)}")
    finally:
        # 重置终端
        print("\x1b[0m")  # 重置所有属性
        colorama.deinit()

运行:

python viewer.py myphoto.jpg

直接

python viewer.py

也可以 

 效果图:

 -和+可以放大缩小

(提示:windows终端 ctrl + 放大字体,ctrl - 缩小字体,缩小字体效果更佳)

 

相关文章:

  • CesiumJS 本地数据瓦片加载南北两极出现圆点问题
  • QML中的WorkerScript
  • TCP 协议算法解析 | RTT / 滑动窗口 / 拥塞控制
  • 时间轮算法:原理、演进与应用实践指南
  • Git和GitCode使用
  • 蓝桥杯-特殊的三角形(dfs/枚举/前缀和)
  • 自学-python-爬虫入门
  • 高项第十五章——项目风险管理
  • 2025年信息系统与未来教育国际学术会议(ISFE 2025)
  • 减少采样空间方法 变成后验概率
  • 不使用自动映射驼峰命名法,直接在接口上使用注解@Results方法映射
  • C++11·部分重要语法III
  • 29_项目
  • linux系统中fstab 各字段详细说明
  • 高清壁纸一站式获取:海量分类,免费无弹窗
  • redis实现简易消息队列
  • Python代码调用Java接口的简单demo
  • 基于本人猜想和尼古拉特斯拉的结合的植物发电站系统
  • DeepSeek-V3-0324 版本升级概要
  • 关于embedding向量模型的知识
  • 拍摄《我们这一代》的肖全开展“江浙沪叙事”
  • 乌美签署矿产协议
  • 美国务院宣布新一轮与伊朗相关的制裁
  • 美乌矿产协议预计最早于今日签署
  • 中国海警位中国黄岩岛领海及周边区域执法巡查
  • “80后”蒋美华任辽宁阜新市副市长