|
1 | 1 | <script lang="ts"> |
2 | 2 | import { clamp, promptConfirmation } from '$lib/util'; |
3 | | - import type { AIBlock, AIPage, Page } from '$lib/types'; |
| 3 | + import type { AIBlock, AIPage, AIRubySegment, Page } from '$lib/types'; |
4 | 4 | import { settings, volumes } from '$lib/settings'; |
5 | 5 | import { |
6 | 6 | showCropper, |
|
59 | 59 | fontSize: string; |
60 | 60 | writingMode: string; |
61 | 61 | lines: string[]; |
| 62 | + rubyLines: AIRubySegment[][] | null; |
62 | 63 | area: number; |
63 | 64 | useMinDimensions: boolean; |
64 | 65 | isOriginalMode: boolean; |
|
74 | 75 | .map(({ block, blockIndex }) => { |
75 | 76 | const { img_height, img_width } = page; |
76 | 77 | const { box, font_size, lines, vertical } = block; |
| 78 | + const ai = aiPage?.blocks.find((item) => item.block_index === blockIndex); |
77 | 79 |
|
78 | 80 | let [_xmin, _ymin, _xmax, _ymax] = box; |
79 | 81 |
|
80 | 82 | // Replace manual ellipsis with proper ellipsis character (…) |
81 | 83 | // Handle both ASCII periods (...) and full-width periods (...) |
82 | | - const processedLines = lines.map((line) => |
| 84 | + const correctedLines = |
| 85 | + ai?.corrected_lines.length === lines.length ? ai.corrected_lines : lines; |
| 86 | + const processedLines = correctedLines.map((line) => |
83 | 87 | line.replace(/\.\.\./g, '…').replace(/.../g, '…') |
84 | 88 | ); |
| 89 | + const rubyLines = |
| 90 | + ai?.ruby_lines?.length === processedLines.length && |
| 91 | + ai.ruby_lines.every( |
| 92 | + (rubyLine, lineIndex) => |
| 93 | + rubyLine.map((segment) => segment.base).join('') === correctedLines[lineIndex] |
| 94 | + ) |
| 95 | + ? ai.ruby_lines |
| 96 | + : null; |
85 | 97 |
|
86 | 98 | const isOriginalMode = $settings.fontSize === 'original'; |
87 | 99 | const isAutoMode = $settings.fontSize === 'auto'; |
|
137 | 149 | fontSize, |
138 | 150 | writingMode: vertical ? 'vertical-rl' : 'horizontal-tb', |
139 | 151 | lines: processedLines, |
| 152 | + rubyLines, |
140 | 153 | area, |
141 | 154 | useMinDimensions: $settings.fontSize !== 'auto' && !isOriginalMode, |
142 | 155 | isOriginalMode, |
143 | 156 | lineLayouts, |
144 | 157 | blockIndex, |
145 | | - ai: aiPage?.blocks.find((item) => item.block_index === blockIndex) |
| 158 | + ai |
146 | 159 | }; |
147 | 160 |
|
148 | 161 | return textBox; |
|
684 | 697 |
|
685 | 698 | <svelte:window onpointerdown={closeAi} /> |
686 | 699 |
|
687 | | -{#each textBoxes as { fontSize, height, left, lines, top, width, writingMode, useMinDimensions, isOriginalMode, lineLayouts, blockIndex, ai }, index (`${volumeUuid}-textBox-${index}`)} |
| 700 | +{#each textBoxes as { fontSize, height, left, lines, rubyLines, top, width, writingMode, useMinDimensions, isOriginalMode, lineLayouts, blockIndex, ai }, index (`${volumeUuid}-textBox-${index}`)} |
688 | 701 | {@const usePerLine = lineLayouts !== null} |
689 | 702 | <div |
690 | 703 | use:handleTextBoxHover={[index, fontSize]} |
|
729 | 742 | style:height={lineLayouts[lineIndex].wrap |
730 | 743 | ? `${lineLayouts[lineIndex].height}px` |
731 | 744 | : undefined} |
732 | | - style:font-size={`${lineLayouts[lineIndex].fontSize}px`}>{line}</span |
| 745 | + style:font-size={`${lineLayouts[lineIndex].fontSize}px`} |
| 746 | + >{#if rubyLines?.[lineIndex]}{#each rubyLines[lineIndex] as segment}{#if segment.reading}<ruby |
| 747 | + >{segment.base}<rt>{segment.reading}</rt></ruby |
| 748 | + >{:else}{segment.base}{/if}{/each}{:else}{line}{/if}</span |
733 | 749 | >{/if}{/each} |
734 | 750 | {:else} |
735 | | - {#each lines as line}<span class="ocr-line">{line}</span>{/each} |
| 751 | + {#each lines as line, lineIndex}<span class="ocr-line" |
| 752 | + >{#if rubyLines?.[lineIndex]}{#each rubyLines[lineIndex] as segment}{#if segment.reading}<ruby |
| 753 | + >{segment.base}<rt>{segment.reading}</rt></ruby |
| 754 | + >{:else}{segment.base}{/if}{/each}{:else}{line}{/if}</span |
| 755 | + >{/each} |
736 | 756 | {/if} |
737 | 757 | </p> |
738 | 758 | {#if ai} |
|
877 | 897 | /* transform (translate onto the quad) is set by positionPerLine */ |
878 | 898 | } |
879 | 899 |
|
| 900 | + .textBox ruby { |
| 901 | + ruby-position: over; |
| 902 | + ruby-align: center; |
| 903 | + } |
| 904 | +
|
| 905 | + .textBox rt { |
| 906 | + font-size: 0.45em; |
| 907 | + font-weight: 400; |
| 908 | + letter-spacing: 0; |
| 909 | + } |
| 910 | +
|
880 | 911 | /* A quad that captured multiple print columns (base text + furigana): |
881 | 912 | the text flows inside the full quad bbox at the block's reference size, |
882 | 913 | wrapping into columns/rows instead of shrinking onto one line. */ |
|
0 commit comments