| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- """
- 表格线绘制功能
- """
- import streamlit as st
- from PIL import Image, ImageDraw, ImageFont
- import json
- import hashlib
- def draw_table_lines_with_numbers(image, structure, line_width=2, show_numbers=True):
- """
- 绘制带编号的表格线(使用线坐标列表)
-
- Args:
- image: PIL Image 对象
- structure: 表格结构字典(包含 horizontal_lines 和 vertical_lines)
- line_width: 线条宽度
- show_numbers: 是否显示编号
-
- Returns:
- 绘制了表格线和编号的图片
- """
- img_with_lines = image.copy()
- draw = ImageDraw.Draw(img_with_lines)
-
- # 尝试加载字体
- try:
- font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 20)
- except:
- font = ImageFont.load_default()
-
- # 使用线坐标列表
- horizontal_lines = structure.get('horizontal_lines', [])
- vertical_lines = structure.get('vertical_lines', [])
- modified_h_lines = structure.get('modified_h_lines', set())
- modified_v_lines = structure.get('modified_v_lines', set())
-
- # 计算绘制范围
- x_start = vertical_lines[0] if vertical_lines else 0
- x_end = vertical_lines[-1] if vertical_lines else img_with_lines.width
- y_start = horizontal_lines[0] if horizontal_lines else 0
- y_end = horizontal_lines[-1] if horizontal_lines else img_with_lines.height
-
- # 绘制横线
- for idx, y in enumerate(horizontal_lines):
- color = (255, 0, 0) if idx in modified_h_lines else (0, 0, 255)
- draw.line([(x_start, y), (x_end, y)], fill=color, width=line_width)
-
- # 绘制行编号
- if show_numbers:
- text = f"R{idx+1}"
- bbox = draw.textbbox((x_start - 35, y - 10), text, font=font)
- draw.rectangle(bbox, fill='white', outline='black')
- draw.text((x_start - 35, y - 10), text, fill=color, font=font)
-
- # 绘制竖线
- for idx, x in enumerate(vertical_lines):
- color = (255, 0, 0) if idx in modified_v_lines else (0, 0, 255)
- draw.line([(x, y_start), (x, y_end)], fill=color, width=line_width)
-
- # 绘制列编号
- if show_numbers:
- text = f"C{idx+1}"
- bbox = draw.textbbox((x - 10, y_start - 25), text, font=font)
- draw.rectangle(bbox, fill='white', outline='black')
- draw.text((x - 10, y_start - 25), text, fill=color, font=font)
- bbox = draw.textbbox((x - 10, y_end + 25), text, font=font)
- draw.rectangle(bbox, fill='white', outline='black')
- draw.text((x - 10, y_end + 25), text, fill=color, font=font)
-
- return img_with_lines
- def draw_clean_table_lines(image, structure, line_width=2, line_color=(0, 0, 0)):
- """
- 绘制纯净的表格线(用于保存)
- - 所有线用统一颜色
- - 不显示编号
-
- Args:
- image: PIL Image 对象
- structure: 表格结构字典
- line_width: 线条宽度
- line_color: 线条颜色,默认黑色 (0, 0, 0)
-
- Returns:
- 绘制了纯净表格线的图片
- """
- img_with_lines = image.copy()
- draw = ImageDraw.Draw(img_with_lines)
-
- horizontal_lines = structure.get('horizontal_lines', [])
- vertical_lines = structure.get('vertical_lines', [])
-
- if not horizontal_lines or not vertical_lines:
- return img_with_lines
-
- # 计算绘制范围
- x_start = vertical_lines[0]
- x_end = vertical_lines[-1]
- y_start = horizontal_lines[0]
- y_end = horizontal_lines[-1]
-
- # 绘制横线
- for y in horizontal_lines:
- draw.line([(x_start, y), (x_end, y)], fill=line_color, width=line_width)
-
- # 绘制竖线
- for x in vertical_lines:
- draw.line([(x, y_start), (x, y_end)], fill=line_color, width=line_width)
-
- return img_with_lines
- def get_structure_hash(structure, line_width, show_numbers):
- """生成结构的哈希值,用于判断是否需要重新绘制"""
- key_data = {
- 'horizontal_lines': structure.get('horizontal_lines', []),
- 'vertical_lines': structure.get('vertical_lines', []),
- 'modified_h_lines': sorted(list(structure.get('modified_h_lines', set()))),
- 'modified_v_lines': sorted(list(structure.get('modified_v_lines', set()))),
- 'line_width': line_width,
- 'show_numbers': show_numbers
- }
-
- key_str = json.dumps(key_data, sort_keys=True)
- return hashlib.md5(key_str.encode()).hexdigest()
- def get_cached_table_lines_image(image, structure, line_width, show_numbers):
- """
- 获取缓存的表格线图片,如果缓存不存在或失效则重新绘制
-
- Args:
- image: PIL Image 对象
- structure: 表格结构字典
- line_width: 线条宽度
- show_numbers: 是否显示编号
-
- Returns:
- 绘制了表格线和编号的图片
- """
- # 初始化缓存
- if 'cached_table_image' not in st.session_state:
- st.session_state.cached_table_image = None
- if 'cached_table_hash' not in st.session_state:
- st.session_state.cached_table_hash = None
-
- # 计算当前结构的哈希
- current_hash = get_structure_hash(structure, line_width, show_numbers)
-
- # 检查缓存是否有效
- if (st.session_state.cached_table_hash == current_hash and
- st.session_state.cached_table_image is not None):
- return st.session_state.cached_table_image
-
- # 缓存失效,重新绘制
- img_with_lines = draw_table_lines_with_numbers(
- image,
- structure,
- line_width=line_width,
- show_numbers=show_numbers
- )
-
- # 更新缓存
- st.session_state.cached_table_image = img_with_lines
- st.session_state.cached_table_hash = current_hash
-
- return img_with_lines
- def clear_table_image_cache():
- """清除表格图片缓存"""
- if 'cached_table_image' in st.session_state:
- st.session_state.cached_table_image = None
- if 'cached_table_hash' in st.session_state:
- st.session_state.cached_table_hash = None
|