55bca92691
Core features: - Class 1 T.30 protocol: full send/receive implementation - HDLC: DLE-stuffing, FCS strip, USR5637 bit-reversal handling - T.4 MH encoder/decoder (1728px A4 standard) - Document pipeline: PDF (Ghostscript), PNG, TIFF input - Width clamping: US Letter 1734px → 1728px fax standard - Cover page: CJK rasterization (TW/CN/JP/EN), TIFF + HTML output - OCR verification: Tesseract 5 with eng+chi_tra, CJK space-tolerant - API server (axum): health, send, jobs, cover, retry, cancel - Background worker: auto-poll queue, speed fallback, retry policy - Modem detection, pool management Real-world test results (2026-07-23): - V90 → 25153038: 4 pages, V.17 12000 bps, 2:33 ✅ - USR5637 → 25153038: 4 pages, V.17 12000 bps, 2:26 ✅ - Both faxes confirmed received on remote machine Tested: loopback (100% pixel match), multi-page, all input formats, cover pages, OCR verify, API endpoints, worker processing. 13 unit tests pass, 0 new clippy warnings.
156 lines
4.7 KiB
Python
156 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
import os
|
|
import sys
|
|
|
|
def create_chinese_image_with_correct_font(output_path, language='chinese'):
|
|
"""Create test image with correct Chinese font"""
|
|
|
|
W, H = 1728, 2291
|
|
img = Image.new('L', (W, H), 255)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# Find Chinese font
|
|
CHINESE_FONTS = [
|
|
# macOS - PingFang (最佳)
|
|
'/System/Library/AssetsV2/com_apple_MobileAsset_Font8/86ba2c91f017a3749571a82f2c6d890ac7ffb2fb.asset/AssetData/PingFang.ttc',
|
|
# macOS - STHeiti (备选)
|
|
'/System/Library/Fonts/STHeiti Medium.ttc',
|
|
# macOS - 其他中文字体
|
|
'/System/Library/Fonts/Supplemental/Arial Unicode.ttf',
|
|
# Linux
|
|
'/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc',
|
|
'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',
|
|
]
|
|
|
|
font_path = None
|
|
for path in CHINESE_FONTS:
|
|
if os.path.exists(path):
|
|
font_path = path
|
|
break
|
|
|
|
if not font_path:
|
|
print("❌ No Chinese font found!")
|
|
print("Available fonts:")
|
|
if os.path.exists('/System/Library/Fonts/'):
|
|
for f in os.listdir('/System/Library/Fonts/'):
|
|
if 'ping' in f.lower() or 'hei' in f.lower() or 'song' in f.lower():
|
|
print(f" - {f}")
|
|
return False
|
|
|
|
print(f"✅ Using font: {font_path}")
|
|
|
|
# Load fonts
|
|
try:
|
|
if 'PingFang' in font_path:
|
|
# PingFang字体索引
|
|
# Index 2 = TC-Light (细体)
|
|
# Index 6 = TC-Medium (中等)
|
|
# Index 10 = TC-Semibold (半粗体)
|
|
font_title = ImageFont.truetype(font_path, 72, index=10)
|
|
font_bold = ImageFont.truetype(font_path, 44, index=6)
|
|
font_normal = ImageFont.truetype(font_path, 44, index=2)
|
|
font_small = ImageFont.truetype(font_path, 36, index=2)
|
|
elif 'STHeiti' in font_path:
|
|
font_title = ImageFont.truetype(font_path, 72)
|
|
font_bold = ImageFont.truetype(font_path, 44)
|
|
font_normal = ImageFont.truetype(font_path, 44)
|
|
font_small = ImageFont.truetype(font_path, 36)
|
|
else:
|
|
font_title = ImageFont.truetype(font_path, 72)
|
|
font_bold = ImageFont.truetype(font_path, 44)
|
|
font_normal = ImageFont.truetype(font_path, 44)
|
|
font_small = ImageFont.truetype(font_path, 36)
|
|
|
|
print("✅ Chinese fonts loaded successfully")
|
|
except Exception as e:
|
|
print(f"❌ Failed to load font: {e}")
|
|
return False
|
|
|
|
# Test texts
|
|
texts = {
|
|
'chinese': {
|
|
'title': '傳真封面頁',
|
|
'content': """收件人:張三
|
|
發件人:李四
|
|
公司:測試科技有限公司
|
|
日期:2024-01-15
|
|
主題:業務合作提案
|
|
頁數:5
|
|
緊急程度:緊急
|
|
|
|
請參閱附件內容,期待您的回覆。
|
|
|
|
謝謝!
|
|
|
|
李四 敬上"""
|
|
},
|
|
'chinese_simplified': {
|
|
'title': '传真封面页',
|
|
'content': """收件人:张三
|
|
发件人:李四
|
|
公司:测试科技有限公司
|
|
日期:2024-01-15
|
|
主题:业务合作提案
|
|
页数:5
|
|
紧急程度:紧急
|
|
|
|
请参阅附件内容,期待您的回复。
|
|
|
|
谢谢!
|
|
|
|
李四 敬上"""
|
|
},
|
|
'mixed': {
|
|
'title': 'FAX 傳真',
|
|
'content': """TO: John Smith (張三)
|
|
FROM: Jane Doe (李四)
|
|
DATE: 2024-01-15
|
|
SUBJECT: Business Proposal (業務提案)
|
|
PAGES: 5
|
|
|
|
This fax contains business documents.
|
|
請參閱附件內容。
|
|
|
|
Best regards,
|
|
Jane Doe"""
|
|
}
|
|
}
|
|
|
|
text_data = texts.get(language, texts['chinese'])
|
|
|
|
# Draw title
|
|
draw.text((100, 100), text_data['title'], fill=0, font=font_title)
|
|
|
|
# Draw line
|
|
draw.line([(100, 200), (W - 100, 200)], fill=0, width=3)
|
|
|
|
# Draw content
|
|
y = 250
|
|
for line in text_data['content'].split('\n'):
|
|
if any(keyword in line for keyword in ['收件人', '发件人', 'TO:', 'FROM:']):
|
|
draw.text((100, y), line, fill=0, font=font_bold)
|
|
else:
|
|
draw.text((100, y), line, fill=0, font=font_normal)
|
|
y += 70
|
|
|
|
# Draw footer
|
|
draw.rectangle([(0, H - 200), (W, H)], fill=0)
|
|
draw.text((100, H - 150), '測試公司 Test Company', fill=255, font=font_small)
|
|
|
|
# Save
|
|
img.save(output_path, dpi=(204, 196))
|
|
print(f"✅ Test image created: {output_path}")
|
|
return True
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python create_chinese_test_image.py <output_path> [language]")
|
|
print("Languages: chinese, chinese_simplified, mixed")
|
|
sys.exit(1)
|
|
|
|
output_path = sys.argv[1]
|
|
language = sys.argv[2] if len(sys.argv) > 2 else 'chinese'
|
|
|
|
create_chinese_image_with_correct_font(output_path, language) |