Spaces:
Running
Running
File size: 9,280 Bytes
156968c 4845952 156968c 4845952 156968c 4845952 156968c 4845952 156968c 4845952 156968c 4845952 156968c 4845952 156968c 4845952 156968c c510530 156968c c510530 156968c c510530 156968c c510530 156968c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
import pandas as pd
import streamlit as st
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
import io
import base64
import os
from datetime import datetime, timedelta
import math
from matplotlib.patches import FancyBboxPatch
from pypinyin import lazy_pinyin, Style
from matplotlib.backends.backend_pdf import PdfPages
def get_font(size=14):
font_path = "simHei.ttc"
if not os.path.exists(font_path):
font_path = "SimHei.ttf"
return font_manager.FontProperties(fname=font_path, size=size)
def get_pinyin_abbr(text):
"""获取文本前两个汉字的拼音首字母"""
if not text:
return ""
# 提取前两个汉字
chars = [c for c in text if '\u4e00' <= c <= '\u9fff']
if len(chars) < 2:
chars = chars + [''] * (2 - len(chars))
else:
chars = chars[:2]
# 获取拼音首字母
pinyin_list = lazy_pinyin(chars, style=Style.FIRST_LETTER)
return ''.join(pinyin_list).upper()
def process_schedule(file):
try:
date_df = pd.read_excel(file, header=None, skiprows=7, nrows=1, usecols=[3])
date_str = pd.to_datetime(date_df.iloc[0, 0]).strftime('%Y-%m-%d')
base_date = pd.to_datetime(date_str).date()
except:
date_str = datetime.today().strftime('%Y-%m-%d')
base_date = datetime.today().date()
try:
df = pd.read_excel(file, header=9, usecols=[1, 2, 4, 5])
df.columns = ['Hall', 'StartTime', 'EndTime', 'Movie']
df['Hall'] = df['Hall'].ffill()
df.dropna(subset=['StartTime', 'EndTime', 'Movie'], inplace=True)
df['Hall'] = df['Hall'].astype(str).str.extract(r'(\d+号)')
df['StartTime_dt'] = pd.to_datetime(df['StartTime'], format='%H:%M', errors='coerce').apply(
lambda t: t.replace(year=base_date.year, month=base_date.month, day=base_date.day) if pd.notnull(t) else t
)
df['EndTime_dt'] = pd.to_datetime(df['EndTime'], format='%H:%M', errors='coerce').apply(
lambda t: t.replace(year=base_date.year, month=base_date.month, day=base_date.day) if pd.notnull(t) else t
)
df.loc[df['EndTime_dt'] < df['StartTime_dt'], 'EndTime_dt'] += timedelta(days=1)
df = df.sort_values(['Hall', 'StartTime_dt'])
merged_rows = []
for hall, group in df.groupby('Hall'):
group = group.sort_values('StartTime_dt')
current = None
for _, row in group.iterrows():
if current is None:
current = row.copy()
else:
if row['Movie'] == current['Movie']:
current['EndTime_dt'] = row['EndTime_dt']
else:
merged_rows.append(current)
current = row.copy()
if current is not None:
merged_rows.append(current)
merged_df = pd.DataFrame(merged_rows)
# 将开始时间统一提前10分钟,结束时间统一提前5分钟
merged_df['StartTime_dt'] = merged_df['StartTime_dt'] - timedelta(minutes=10)
merged_df['EndTime_dt'] = merged_df['EndTime_dt'] - timedelta(minutes=5)
merged_df['StartTime_str'] = merged_df['StartTime_dt'].dt.strftime('%H:%M')
merged_df['EndTime_str'] = merged_df['EndTime_dt'].dt.strftime('%H:%M')
return merged_df[['Hall', 'Movie', 'StartTime_str', 'EndTime_str']], date_str
except:
return None, date_str
def create_print_layout(data, date_str):
if data is None or data.empty:
return None
# 创建PNG图像 - 使用A4纸张大小并最大化内容
png_fig = plt.figure(figsize=(8.27, 11.69), dpi=300)
png_ax = png_fig.add_subplot(111)
png_ax.set_axis_off()
# 为PNG设置更小的边距以最大化内容
png_fig.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.02)
# 创建PDF图像 - 使用A4纸张大小
pdf_fig = plt.figure(figsize=(8.27, 11.69), dpi=300)
pdf_ax = pdf_fig.add_subplot(111)
pdf_ax.set_axis_off()
# 为PDF设置更小的边距
pdf_fig.subplots_adjust(left=0.02, right=0.98, top=0.98, bottom=0.02)
# 处理两个图形的共同函数
def process_figure(fig, ax, is_pdf=False):
# Pre-load fonts
date_font = get_font(12)
# 使用更大的字体以最大化利用纸张空间
font_size_multiplier = 1.2
movie_font_size = 14 * font_size_multiplier
hall_font_size = movie_font_size * 0.8
hall_font = get_font(hall_font_size)
movie_font = get_font(movie_font_size)
ax.text(0.00, 1.00, date_str, fontsize=12 * font_size_multiplier, color='#A9A9A9',
ha='left', va='top', fontproperties=date_font, transform=ax.transAxes, zorder=2)
halls = sorted(data['Hall'].unique(), key=lambda h: int(h.replace('号','')) if h else 0)
total_lines = sum(len(data[data['Hall'] == hall]) for hall in halls) + (len(halls) - 1)
available_height = 0.98 - 0.02 # 增加可用高度
line_spacing = available_height / total_lines if total_lines > 0 else 0.04
y_position = 0.98
for hall in halls:
hall_data = data[data['Hall'] == hall]
y_block_top = y_position
hall_num = hall.replace("号", "")
hall_text = f"${hall_num}^{{\\#}}$"
movie_count = 1
for _, row in hall_data.iterrows():
ax.text(0.03, y_position, hall_text if movie_count == 1 else "",
fontsize=hall_font_size, fontweight='bold',
ha='left', va='top', fontproperties=hall_font,
transform=ax.transAxes, zorder=2)
# 获取电影名前两个字的拼音首字母
pinyin_abbr = get_pinyin_abbr(row['Movie'])
# 电影名称左对齐,限制在0.2到0.6的区域内
ax.text(0.20, y_position, f"{movie_count}. {pinyin_abbr} {row['Movie']}",
fontsize=movie_font_size, ha='left', va='top', fontproperties=movie_font,
transform=ax.transAxes, zorder=2, clip_on=True,
bbox=dict(boxstyle="square,pad=0.0", fc="none", ec="none", alpha=0))
# 时间信息右对齐,固定在0.95位置
ax.text(0.95, y_position, f"{row['StartTime_str']} - {row['EndTime_str']}",
fontsize=movie_font_size, ha='right', va='top', fontproperties=movie_font,
transform=ax.transAxes, zorder=2)
y_position -= line_spacing
movie_count += 1
y_block_bottom = y_position
y_position -= line_spacing
rect = FancyBboxPatch((0.03, y_block_bottom), 0.94, y_block_top - y_block_bottom,
boxstyle="round,pad=0.005,rounding_size=0.005",
edgecolor='gray', facecolor='white',
linewidth=0.8, zorder=1, transform=ax.transAxes)
ax.add_patch(rect)
# 处理PNG图形
process_figure(png_fig, png_ax)
# 处理PDF图形
process_figure(pdf_fig, pdf_ax, is_pdf=True)
# 保存PNG图像 - 使用最小边距以最大化内容
png_buffer = io.BytesIO()
png_fig.savefig(png_buffer, format='png', bbox_inches='tight', pad_inches=0.05)
png_buffer.seek(0)
image_base64 = base64.b64encode(png_buffer.getvalue()).decode()
plt.close(png_fig)
# 保存PDF文件 - 使用最小边距
pdf_buffer = io.BytesIO()
with PdfPages(pdf_buffer) as pdf:
pdf.savefig(pdf_fig, bbox_inches='tight', pad_inches=0.05)
pdf_buffer.seek(0)
pdf_base64 = base64.b64encode(pdf_buffer.getvalue()).decode()
plt.close(pdf_fig)
return {
'png': f"data:image/png;base64,{image_base64}",
'pdf': f"data:application/pdf;base64,{pdf_base64}"
}
def display_pdf(base64_pdf):
# 在Streamlit中显示PDF
pdf_display = f"""
<iframe src="{base64_pdf}" width="100%" height="800" type="application/pdf"></iframe>
"""
return pdf_display
st.set_page_config(page_title="LED 屏幕时间表打印", layout="wide")
st.title("LED 屏幕时间表打印")
uploaded_file = st.file_uploader("选择打开【放映时间核对表.xls】文件", accept_multiple_files=False, type=["xls"])
if uploaded_file:
with st.spinner("文件正在处理中,请稍候..."):
schedule, date_str = process_schedule(uploaded_file)
if schedule is not None:
output = create_print_layout(schedule, date_str)
# 创建选项卡以切换PNG和PDF视图
tab1, tab2 = st.tabs(["PDF 预览", "PNG 预览"])
with tab1:
st.markdown(display_pdf(output['pdf']), unsafe_allow_html=True)
with tab2:
st.image(output['png'], use_container_width=True)
else:
st.error("无法处理文件,请检查文件格式或内容是否正确。")
|