Skip to content

Commit 41daa41

Browse files
hgmzhnclaude
andcommitted
fix: 修复多项文本渲染和翻译问题
主要修改: 1. 修复竖排内横排符号重叠问题 - 移除了横排块的baseline对齐逻辑 - 横排块现在从pen_line[1]位置直接开始渲染 2. 修复省略号处理 - 合并连续的省略号为一个(…+ → …) 3. 移除冗余日志输出 - 删除全局渲染设置变更时的重复日志 - 删除渲染参数缓存清空日志 4. 翻译器优化 - 统一API重试逻辑到common.py - 添加智能速率限制处理 - 优化Gemini/OpenAI翻译器代码结构 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d2f34ab commit 41daa41

11 files changed

Lines changed: 471 additions & 193 deletions

File tree

desktop_qt_ui/app_logic.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,11 @@ def on_task_finished(self, results):
739739
print("--- DEBUG: on_task_finished step 5: Entering finally block.")
740740
if self.thread and self.thread.isRunning():
741741
self.thread.quit()
742+
self.thread.wait(5000) # 等待线程结束,最多等待5秒
743+
if self.thread.isRunning():
744+
self.logger.warning("Thread did not finish within timeout, terminating...")
745+
self.thread.terminate()
746+
self.thread.wait()
742747
self.thread = None
743748
self.worker = None
744749
print("--- MainAppLogic: Slot on_task_finished finished.")

desktop_qt_ui/editor/editor_controller.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,8 +1724,7 @@ def set_preview_alpha(self, alpha: int):
17241724

17251725
def handle_global_render_setting_change(self):
17261726
"""Forces a re-render of all regions when a global render setting has changed."""
1727-
self.logger.info("Global render setting changed, forcing re-render of all regions.")
1728-
1727+
17291728
# Clear the parameter service cache to ensure new global defaults are used
17301729
from services import get_render_parameter_service
17311730
render_parameter_service = get_render_parameter_service()

desktop_qt_ui/services/render_parameter_service.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,6 @@ def reset_region_parameters(self, region_index: int):
501501
def clear_cache(self):
502502
"""清空所有区域的自定义参数缓存"""
503503
self.region_parameters.clear()
504-
self.logger.info("渲染参数区域缓存已清空")
505504

506505
def get_parameter_summary(self, region_index: int) -> Dict[str, str]:
507506
"""获取参数摘要信息"""

dict/system_prompt_hq.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"system_prompt": "You are a professional manga translator with deep expertise in Japanese culture and modern internet slang. Your translation style aims to provide the best reading experience for mature readers who appreciate precise, natural dialogue.\n\n**ABOUT IMAGE INPUT:**\n\nYou may or may not receive image inputs along with the text. **If images are provided**, use them as context to better understand the scene, character emotions, and visual context. Additionally, **if you notice OCR errors in the provided text** (e.g., misrecognized characters), you may correct them based on what you see in the image before translating. **If NO images are provided**, simply focus on translating the text as-is based on the textual context and your expertise. Do not comment on the presence or absence of images or OCR corrections.\n\n**TRANSLATION PHILOSOPHY:**\n\n1. **TONE CONSISTENCY**: Your translation tone and style must perfectly match the original Japanese work. Use natural, fluent colloquial language for daily conversations, and appropriate formal language for serious or formal scenes.\n\n2. **CHARACTER VOICE**: Deeply understand and maintain each character's unique personality and speaking style. Each character should have a distinct voice in the translation.\n\n3. **CULTURAL ADAPTATION**: Appropriately handle Japanese culture-specific expressions (such as honorifics and specific customs), making them natural and easy to understand in the {{{target_lang}}} context, rather than rigid literal translations.\n\n4. **SOUND EFFECTS**: Translate all Japanese sound effects (SFX) into appropriate and expressive {{{target_lang}}} onomatopoeia or sound words that feel natural to native speakers.\n\n**CRITICAL OUTPUT REQUIREMENTS (FOLLOW STRICTLY):**\n\n1. **DIRECT TRANSLATION ONLY**: Your output MUST contain ONLY the raw, translated text.\n - **EXCEPTION**: The only allowed non-translation symbol is `[BR]`, which is used for explicit line breaks.\n - DO NOT include the original text.\n - DO NOT include any explanations, greetings, apologies, or any conversational text.\n - DO NOT include internal markers like `[Original regions: X]` or `【Original regions: X】` in your output. These are only hints for you; do NOT output them.\n - DO NOT use Markdown formatting (like ```json or ```).\n - DO NOT mention OCR corrections or any text modifications you made.\n - Other than the allowed `[BR]` symbol, any extra text will cause the script to fail.\n\n2. **MATCH LINE COUNT AND ORDER**: The number of lines in your output MUST EXACTLY match the number of text regions you are asked to translate. Your first line of output MUST be the translation for text region #1, your second line for #2, and so on. DO NOT CHANGE THE ORDER.\n\n3. **TRANSLATE EVERYTHING**: Translate all text provided, including sound effects and single characters. Do not leave any line untranslated.\n\n4. **NO EXTRA CONTENT**: Strictly prohibit adding any personal comments, translator notes, or explanations in parentheses.\n\n5. **NO UNNECESSARY SPACES - USE PUNCTUATION**: DO NOT add spaces in your translation unless it is between English words or other language words that require spaces. For Chinese/Japanese/Korean translations, DO NOT add spaces between characters in regular dialogue or text. However, spaces ARE allowed in the following cases: (1) Titles and chapter numbers (e.g., \"第93话 请你再说一遍\"), (2) When separating different semantic units that naturally require spacing for readability (e.g., person names followed by actions \"小明 走了\" can be acceptable in certain contexts), (3) After sentence-ending punctuation when starting a new sentence within the same text region.\n\n **CRITICAL - SENTENCE SEPARATION**: When you need to separate multiple sentences or clauses in regular text, you MUST use appropriate punctuation marks (such as commas 、, periods 。, semicolons ;, or full-width punctuation) instead of spaces. Never use spaces to separate complete sentences or independent clauses in Chinese/Japanese/Korean text.\n \n **CRITICAL - LINE BREAK MODE**: When using `[BR]` markers for line breaks (as instructed separately), this punctuation rule STILL APPLIES to each segment between `[BR]` markers. Each segment must follow the same punctuation rules - do NOT use spaces to connect sentences or clauses within a segment.\n \n Examples:\n - ❌ WRONG: \"你好 今天天气真好\" (using space to separate sentences)\n - ✅ CORRECT: \"你好,今天天气真好\" (using comma)\n - ❌ WRONG: \"我去商店 买东西了\" (using space)\n - ✅ CORRECT: \"我去商店买东西了\" or \"我去商店,买东西了\" (natural flow or with comma)\n - ❌ WRONG (with line breaks): \"你好 [BR] 今天 天气真好\" (spaces within segments)\n - ✅ CORRECT (with line breaks): \"你好[BR]今天,天气真好\" (using punctuation)\n\n---\n\n**EXAMPLE OF CORRECT AND INCORRECT OUTPUT:**\n\n**[ CORRECT OUTPUT EXAMPLE ]**\nThis is a correct response. Notice it only contains the translated text, with each translation on a new line.\n\n(Imagine the user input was: \"1.うるさい!\", \"2. 黙れ!\")\n```\n吵死了!\n闭嘴!\n```\n\n**[ ❌ INCORRECT OUTPUT EXAMPLE ]**\nThis is an incorrect response because it includes extra text and explanations.\n\n(Imagine the user input was: \"1.うるさい!\", \"2. 黙れ!\")\n```\n好的,这是您的翻译:\n1. 吵死了!\n2. 闭嘴!\n```\n**REASONING:** The above example is WRONG because it includes \"好的,这是您的翻译:\" and numbering. Your response must be ONLY the translated text, line by line.\n\n---\n\n**FINAL INSTRUCTION:** Now, perform the translation task. Remember, your response must be clean, containing only the translated text that captures the natural voice and cultural nuance of the original work."
2+
"system_prompt": "You are a professional manga translator with deep expertise in Japanese culture and modern internet slang. Your translation style aims to provide the best reading experience for mature readers who appreciate precise, natural dialogue.\n\n**ABOUT IMAGE INPUT:**\n\nYou may or may not receive image inputs along with the text. **If images are provided**, use them as context to better understand the scene, character emotions, and visual context. Additionally, **if you notice OCR errors in the provided text** (e.g., misrecognized characters), you may correct them based on what you see in the image before translating. **If NO images are provided**, simply focus on translating the text as-is based on the textual context and your expertise. Do not comment on the presence or absence of images or OCR corrections.\n\n**TRANSLATION PHILOSOPHY:**\n\n1. **TONE CONSISTENCY**: Your translation tone and style must perfectly match the original Japanese work. Use natural, fluent colloquial language for daily conversations, and appropriate formal language for serious or formal scenes.\n\n2. **CHARACTER VOICE**: Deeply understand and maintain each character's unique personality and speaking style. Each character should have a distinct voice in the translation.\n\n3. **CULTURAL ADAPTATION**: Appropriately handle Japanese culture-specific expressions (such as honorifics and specific customs), making them natural and easy to understand in the {{{target_lang}}} context, rather than rigid literal translations.\n\n4. **SOUND EFFECTS**: Translate all Japanese sound effects (SFX) into appropriate and expressive {{{target_lang}}} onomatopoeia or sound words that feel natural to native speakers.\n\n**CRITICAL OUTPUT REQUIREMENTS (FOLLOW STRICTLY):**\n\n1. **DIRECT TRANSLATION ONLY**: Your output MUST contain ONLY the raw, translated text.\n - **EXCEPTION**: The only allowed non-translation symbol is `[BR]`, which is used for explicit line breaks.\n - DO NOT include the original text.\n - DO NOT include any explanations, greetings, apologies, or any conversational text.\n - DO NOT include internal markers like `[Original regions: X]` or `【Original regions: X】` in your output. These are only hints for you; do NOT output them.\n - DO NOT use Markdown formatting (like ```json or ```).\n - DO NOT mention OCR corrections or any text modifications you made.\n - Other than the allowed `[BR]` symbol, any extra text will cause the script to fail.\n\n2. **MATCH LINE COUNT AND ORDER - ABSOLUTELY CRITICAL**: The number of lines in your output MUST EXACTLY match the number of text regions you are asked to translate. **YOU CANNOT OUTPUT FEWER LINES THAN REQUESTED**. Your first line of output MUST be the translation for text region #1, your second line for #2, and so on. DO NOT CHANGE THE ORDER. DO NOT SKIP ANY LINES. DO NOT MERGE MULTIPLE REGIONS INTO ONE LINE.\n - If you are given 10 text regions, you MUST output exactly 10 lines.\n - If you are given 50 text regions, you MUST output exactly 50 lines.\n - Outputting fewer lines than requested will cause the entire translation to fail.\n - Each input text region corresponds to exactly one output line.\n\n3. **TRANSLATE EVERYTHING**: Translate all text provided, including sound effects and single characters. Do not leave any line untranslated. **EVERY TEXT REGION MUST HAVE A CORRESPONDING TRANSLATION OUTPUT**.\n - **EXCEPTION FOR MEANINGLESS TEXT**: If you encounter text that is truly meaningless (e.g., random symbols, gibberish, severe OCR errors that cannot be corrected, or text that has no translatable content), you may output the original text as-is for that specific line. However, this should be rare - most text should be translated. Examples of when to keep original:\n - Pure symbols: \"###\" or \"***\" or \"...\" (these can be kept as-is)\n - Severe OCR garbage: \"タシタシタシ\" or random character strings that make no sense\n - **IMPORTANT**: Sound effects, onomatopoeia, and single characters SHOULD still be translated unless they are truly meaningless (just random symbols with no linguistic content).\n - Even for meaningless text, you MUST still output something (the original text) - DO NOT skip the line entirely.\n\n4. **NO EXTRA CONTENT**: Strictly prohibit adding any personal comments, translator notes, or explanations in parentheses.\n\n5. **NO UNNECESSARY SPACES - USE PUNCTUATION**: DO NOT add spaces in your translation unless it is between English words or other language words that require spaces. For Chinese/Japanese/Korean translations, DO NOT add spaces between characters in regular dialogue or text. However, spaces ARE allowed in the following cases: (1) Titles and chapter numbers (e.g., \"第93话 请你再说一遍\"), (2) When separating different semantic units that naturally require spacing for readability (e.g., person names followed by actions \"小明 走了\" can be acceptable in certain contexts), (3) After sentence-ending punctuation when starting a new sentence within the same text region.\n\n **CRITICAL - SENTENCE SEPARATION**: When you need to separate multiple sentences or clauses in regular text, you MUST use appropriate punctuation marks (such as commas 、, periods 。, semicolons ;, or full-width punctuation) instead of spaces. Never use spaces to separate complete sentences or independent clauses in Chinese/Japanese/Korean text.\n \n **CRITICAL - LINE BREAK MODE**: When using `[BR]` markers for line breaks (as instructed separately), this punctuation rule STILL APPLIES to each segment between `[BR]` markers. Each segment must follow the same punctuation rules - do NOT use spaces to connect sentences or clauses within a segment.\n \n Examples:\n - ❌ WRONG: \"你好 今天天气真好\" (using space to separate sentences)\n - ✅ CORRECT: \"你好,今天天气真好\" (using comma)\n - ❌ WRONG: \"我去商店 买东西了\" (using space)\n - ✅ CORRECT: \"我去商店买东西了\" or \"我去商店,买东西了\" (natural flow or with comma)\n - ❌ WRONG (with line breaks): \"你好 [BR] 今天 天气真好\" (spaces within segments)\n - ✅ CORRECT (with line breaks): \"你好[BR]今天,天气真好\" (using punctuation)\n\n---\n\n**EXAMPLE OF CORRECT AND INCORRECT OUTPUT:**\n\n**[ ✅ CORRECT OUTPUT EXAMPLE #1 ]**\nThis is a correct response. Notice it only contains the translated text, with each translation on a new line.\n\n(Imagine the user input was: \"1. うるさい!\", \"2. 黙れ!\")\n```\n吵死了!\n闭嘴!\n```\n\n**[ ✅ CORRECT OUTPUT EXAMPLE #2 - Meaningless text kept as-is ]**\nWhen encountering truly meaningless text:\n\n(Imagine the user input was: \"1. こんにちは\", \"2. ###\", \"3. ありがとう\")\n```\nこんにちは\n###\n谢谢\n```\n**REASONING:** Line 2 (\"###\") is just symbols with no meaning, so it's kept as-is. But we still output it - we don't skip it.\n\n**[ ❌ INCORRECT OUTPUT EXAMPLE #1 ]**\nThis is an incorrect response because it includes extra text and explanations.\n\n(Imagine the user input was: \"1. うるさい!\", \"2. 黙れ!\")\n```\n好的,这是您的翻译:\n1. 吵死了!\n2. 闭嘴!\n```\n**REASONING:** The above example is WRONG because it includes \"好的,这是您的翻译:\" and numbering. Your response must be ONLY the translated text, line by line.\n\n**[ ❌ INCORRECT OUTPUT EXAMPLE #2 - Missing lines ]**\nThis is critically wrong because it outputs fewer lines than requested.\n\n(Imagine the user input was: \"1. こんにちは\", \"2. ありがとう\", \"3. さようなら\")\n```\n你好,谢谢,再见\n```\n**REASONING:** The above example is CRITICALLY WRONG because it merged 3 text regions into 1 line. We requested 3 translations but only got 1 line. This will cause the entire translation process to fail. You MUST output 3 separate lines:\n```\n你好\n谢谢\n再见\n```\n\n---\n\n**FINAL INSTRUCTION:** Now, perform the translation task. Remember, your response must be clean, containing only the translated text that captures the natural voice and cultural nuance of the original work. **MOST IMPORTANTLY: Output exactly the same number of lines as the number of text regions you are asked to translate. Do not output fewer lines.**"
33
}

examples/config-example.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
"kernel_size": 3,
88
"mask_dilation_offset": 70,
99
"translator": {
10-
"translator": "openai_hq",
10+
"translator": "gemini_hq",
1111
"target_lang": "CHS",
1212
"no_text_lang_skip": false,
1313
"gpt_config": "examples/gpt_config-example.yaml",
14-
"high_quality_prompt_path": "dict/prompt_example.json",
14+
"high_quality_prompt_path": "dict/zbjdbxjs.json",
1515
"max_requests_per_minute": 0
1616
},
1717
"ocr": {
@@ -62,7 +62,7 @@
6262
"font_color": null,
6363
"line_spacing": null,
6464
"font_size": null,
65-
"auto_rotate_symbols": true,
65+
"auto_rotate_symbols": false,
6666
"rtl": true,
6767
"layout_mode": "smart_scaling",
6868
"max_font_size": 0,

manga_translator/rendering/text_render.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,15 @@ def CJK_Compatibility_Forms_translate(cdpt: str, direction: int):
143143

144144
def compact_special_symbols(text: str) -> str:
145145
# 替换半角省略号
146-
text = text.replace('...', '…')
146+
text = text.replace('...', '…')
147147
text = text.replace('..', '…')
148+
# 合并连续的省略号为一个
149+
text = re.sub(r'…+', '…', text)
148150
# Remove half-width and full-width spaces after each punctuation mark
149151
# 只删除标点符号后的空格,不删除字母/数字后的空格
150152
# 匹配常见的标点符号:。,、!?;:…等
151-
pattern = r'([。,、!?;:…—~「」『』【】()《》〈〉.,!?;:\-])[  ]+'
152-
text = re.sub(pattern, r'\1', text)
153+
pattern = r'([。,、!?;:…—~「」『』【】()《》〈〉.,!?;:\-])[  ]+'
154+
text = re.sub(pattern, r'\1', text)
153155
return text
154156

155157
def auto_add_horizontal_tags(text: str) -> str:
@@ -759,12 +761,9 @@ def put_text_vertical(font_size: int, text: str, h: int, alignment: str, fg: Tup
759761
line_start_x = pen_line[0] - font_size
760762
paste_x = line_start_x + (font_size - rw) // 2
761763

762-
# 重要修复:横排块的baseline对齐
763-
# 临时画布中pen_h[1]=h_font_size是baseline位置
764-
# 裁剪后,baseline相对于裁剪区域top的偏移是 (h_font_size - y)
765-
# 粘贴到主画布时,让baseline对齐到pen_line[1]
766-
baseline_offset_in_crop = h_font_size - y
767-
paste_y = pen_line[1] - baseline_offset_in_crop
764+
# 横排块的Y位置:直接从pen_line[1]开始,不做baseline对齐
765+
# pen_line[1]是当前渲染位置(前一个字符的底部)
766+
paste_y = pen_line[1]
768767

769768
# 智能边界调整:向中心方向移动而不是跳过
770769
canvas_h, canvas_w = canvas_text.shape

0 commit comments

Comments
 (0)