Research Phase 8 plan 08-02: image display fix in the native text rendering path. Documents the unified max-size approach (1080x1920), footnote width-only sizing, and three entry points that need changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
28 KiB
Phase 8: 图片显示修复 - Research
Researched: 2026-05-23 Domain: DTCoreText image attachment sizing, WXRead alignment Confidence: HIGH
Summary
Phase 8 plan 08-02 focuses on fixing image display in the native text rendering path (DTCoreText). Three image types have sizing issues: (1) qrbodyPic images can overflow page height because no max size constraint is applied, (2) cover images use screen-size baselines but lack a unified ceiling, (3) footnote images have inconsistent height calculations across three separate code paths.
The core fix is to add a unified maximum size constraint (CGSize(width: 1080, height: 1920)) to ALL image attachments in prepareHTMLElementForReaderRendering, applied BEFORE any type-specific handling. This directly mirrors WXRead's _WRPostProcessElementTree approach. The fix is surgical: one new code block at the top of the existing function, plus removal of redundant height logic in two other locations.
Primary recommendation: Add a unified max-size block at the top of prepareHTMLElementForReaderRendering that constrains all images to 1080x1920 via aspect-ratio-preserving scaling. Then simplify footnote handling to width-only (no explicit height), matching WXRead's replace.css.
<user_constraints>
User Constraints (from CONTEXT.md)
Locked Decisions
- D-01: Unified max image size
CGSizeMake(1080, 1920)for all image attachments - D-02: Scale proportionally when exceeding max width (matching WXRead
_WRPostProcessElementTree) - D-03: Implementation location:
prepareHTMLElementForReaderRendering, BEFORE existing footnote/cover special handling - D-04: Cover images keep screen-size base (
UIScreen.main.bounds.insetBy(dx: 20, dy: 28)), constrained by unified max - D-05: Keep
configureCoverIfNeededUIImageView path unchanged - D-06: Cover images still processed via cover branch in
prepareHTMLElementForReaderRendering, but must not exceed unified max - D-07: Footnote images: only set
width:1em, no height (align with WXReadreplace.css) - D-08: Remove footnote height calculation in
prepareHTMLElementForReaderRendering(pointSize * 0.54) - D-09: Remove height override in
normalizeInlineAttachments(pointSize * 0.14) - D-10: Keep CSS
width:1eminnormalizeAttachmentHTMLMarkers, removeheight:1em - D-11: No special handling for
qrbodyPic— unified max size implicitly fixes overflow - D-12: Keep existing CSS rules for
qrbodyPicunchanged
Claude's Discretion
- Whether to auto-add
bodyPicclass to all images (like WXRead does) - Whether
wr-vertical-center-stylesemantic marker is needed (Phase 7 already handles this) - Specific implementation details of the unified max-size block
Deferred Ideas (OUT OF SCOPE)
- Image caching mechanism (belongs to plan 08-01)
wr-vertical-center-stylefull implementation (Phase 7 already completed)- Image tap-to-zoom feature (new capability, not in scope) </user_constraints>
<phase_requirements>
Phase Requirements
| ID | Description | Research Support |
|---|---|---|
| QUAL-01 | Cache layout frame / pagination results | Not in scope for 08-02 (belongs to 08-01) |
| QUAL-02 | Improve pagination quality for complex illustrated chapters — reduce bad page breaks, orphan/widow lines, abnormal whitespace around images | Image sizing fix directly addresses image-related pagination quality |
| QUAL-03 | Image/attachment sizing strategy, dark mode adaptation, page background — must have verifiable processing rules, not rely on DTCoreText defaults | Unified max size + explicit CSS rules provide verifiable rules |
| QUAL-04 | Pagination improvements must not significantly degrade first-screen time, re-pagination time, or interaction smoothness | Image sizing is a lightweight operation in willFlushCallback, negligible performance impact |
| </phase_requirements> |
Architectural Responsibility Map
| Capability | Primary Tier | Secondary Tier | Rationale |
|---|---|---|---|
| Image max-size constraint | Swift willFlushCallback (renderer) |
CSS replaceCSS |
Swift handles absolute pixel ceiling; CSS handles responsive width |
| Footnote image sizing | CSS (width:1em in HTML preprocessing) |
Swift (vertical alignment) | CSS controls width; Swift only sets alignment |
| Cover image sizing | Swift (prepareHTMLElementForReaderRendering) |
configureCoverIfNeeded (view layer) |
Swift constrains in attributed string; view layer only extracts for UIImageView display |
| Page-break control around images | Layouter (pagination) | CSS (page-break-inside: avoid) |
Layouter decides actual breaks; CSS provides hints |
Standard Stack
Core
| Library | Version | Purpose | Why Standard |
|---|---|---|---|
| DTCoreText | (CocoaPod, project-local) | HTML/CSS to NSAttributedString | Existing project dependency; provides DTTextAttachment, willFlushCallback |
| UIKit | iOS SDK | UIScreen.main.bounds for cover sizing |
Platform standard |
Supporting
| Library | Version | Purpose | When to Use |
|---|---|---|---|
| Foundation | iOS SDK | NSRegularExpression for HTML preprocessing |
Already used throughout RDEPUBTextRendererSupport |
Alternatives Considered
| Instead of | Could Use | Tradeoff |
|---|---|---|
Swift-side max size in willFlushCallback |
CSS max-height in replaceCSS |
CSS approach is simpler but DTCoreText CSS parser may not support max-height reliably for attachments; Swift is authoritative |
Removing DTMaxImageSize from builder options |
Keeping both layers | Keeping both is safer — DTMaxImageSize is the first line of defense at attachment creation time; willFlushCallback is the second pass |
Package Legitimacy Audit
No new packages are installed in this phase. All changes are to existing Swift source files.
| Package | Registry | Age | Downloads | Source Repo | slopcheck | Disposition |
|---|---|---|---|---|---|---|
| (none) | — | — | — | — | — | No new packages |
Architecture Patterns
Current Image Processing Pipeline
HTML input
|
v
normalizeAttachmentHTMLMarkers() <-- HTML regex: adds inline styles to <img> tags
| (footnote: width:1em;height:1em)
| (cover: adds rd-front-cover-image class)
v
DTHTMLAttributedStringBuilder <-- Creates DTTextAttachment with DTMaxImageSize
| (currently screenBounds.size, ~353x757)
| DTCoreText sets displaySize = min(original, max)
v
willFlushCallback <-- prepareHTMLElementForReaderRendering()
| Currently: footnote → height calc, cover → screen scale
| MISSING: unified max-size for ALL images
v
normalizeReadingAttributes() <-- normalizeAttachmentDisplayIfNeeded()
| Currently: footnote → height override (0.14*pt)
| cover → maxWidth override
v
configureCoverIfNeeded() <-- View layer: extracts cover image for UIImageView
|
v
normalizeInlineAttachments() <-- View layer: footnote → height override (0.14*pt)
Recommended Pipeline After Fix
HTML input
|
v
normalizeAttachmentHTMLMarkers() <-- CHANGED: footnote <img> only gets width:1em (no height)
v
DTHTMLAttributedStringBuilder <-- CHANGED: DTMaxImageSize → CGSizeMake(1080, 1920)
v
willFlushCallback <-- prepareHTMLElementForReaderRendering()
| NEW: unified max-size block for ALL images first
| THEN: footnote → only verticalAlignment + inline
| THEN: cover → screen-size scale (capped by max)
v
normalizeReadingAttributes() <-- normalizeAttachmentDisplayIfNeeded()
| CHANGED: footnote path removed (no height override)
| cover path can remain as fallback
v
configureCoverIfNeeded() <-- UNCHANGED
v
normalizeInlineAttachments() <-- CHANGED: footnote height override removed
Pattern 1: Unified Max-Size Block in prepareHTMLElementForReaderRendering
What: A new code block at the top of the function, before any type-specific handling, that constrains ALL image attachments to 1080x1920.
When to use: Every image attachment that enters willFlushCallback.
Example:
// Source: WXRead WREpubTypesetter.m §672-701 (_WRPostProcessElementTree)
// Placed BEFORE existing footnote/cover handling in prepareHTMLElementForReaderRendering
static func prepareHTMLElementForReaderRendering(
_ element: DTHTMLElement,
style: RDEPUBTextRenderStyle
) {
guard let attachment = element.textAttachment else { return }
// --- NEW: Unified max image size (aligns with WXRead _WRPostProcessElementTree) ---
let maxImageSize = CGSize(width: 1080, height: 1920)
let originalSize = attachment.originalSize
if originalSize.width > maxImageSize.width || originalSize.height > maxImageSize.height {
let scale = min(maxImageSize.width / max(originalSize.width, 1),
maxImageSize.height / max(originalSize.height, 1))
attachment.displaySize = CGSize(
width: round(originalSize.width * scale),
height: round(originalSize.height * scale)
)
}
// ... existing footnote/cover handling follows ...
}
Pattern 2: Footnote Width-Only Sizing
What: Footnote images get width:1em in HTML preprocessing, with no explicit height. DTCoreText calculates height from aspect ratio.
When to use: In normalizeAttachmentHTMLMarkers for qqreader-footnote images.
Example:
// Source: WXRead replace.css §100-103 (.qqreader-footnote { width: 1em; })
// Changed: removed "height:1em" from styleFragments
normalized = replaceMatches(
using: footnoteRegex,
in: normalized
) { tag in
mergeHTMLAttributes(
into: tag,
requiredClass: nil,
styleFragments: [
"width:1em",
// "height:1em" <-- REMOVED per D-10
"vertical-align:middle",
"display:inline-block"
]
)
}
Anti-Patterns to Avoid
- Separate max-size blocks for each image type: WXRead applies one unified block to ALL images. Do not duplicate the scaling logic for qrbodyPic, cover, and footnote separately.
- Removing
DTMaxImageSizefrom builder options: The DTCoreText-level max size is the first line of defense (applied during attachment creation). ThewillFlushCallbackmax size is the second pass. Keep both. - Setting explicit height on footnote images: WXRead only sets
width:1emon.qqreader-footnote. DTCoreText'ssetDisplaySize:withMaxDisplaySize:handles width-only cases by calculating height from aspect ratio (line 231-236 of DTTextAttachment.m).
Don't Hand-Roll
| Problem | Don't Build | Use Instead | Why |
|---|---|---|---|
| Aspect ratio calculation | Custom scaling math | DTCoreText's DTCGSizeThatFitsKeepingAspectRatio or the existing min(w/maxW, h/maxH) pattern |
Consistent with DTCoreText internals |
| Image type detection | New classification system | Existing CSS class + filename detection (lowercasedClasses, lowercasedPath) |
Already works, battle-tested in Phase 7 |
Common Pitfalls
Pitfall 1: DTMaxImageSize vs willFlushCallback Ordering
What goes wrong: If the max-size constraint is only in willFlushCallback, DTCoreText's initial setDisplaySize:withMaxDisplaySize: uses the old (screen-size) max. The willFlushCallback then overrides it. This works but the intermediate state could confuse debugging.
Why it happens: DTMaxImageSize is consumed at attachment creation time; willFlushCallback runs after.
How to avoid: Update BOTH: change DTMaxImageSize in dtOptions() to CGSize(width: 1080, height: 1920) AND add the max-size block in prepareHTMLElementForReaderRendering. The willFlushCallback block is the authoritative constraint; DTMaxImageSize is the first-pass optimization.
Warning signs: If only one is updated, images may briefly appear at wrong size before being corrected.
Pitfall 2: Footnote Aspect Ratio Without Explicit Height
What goes wrong: After removing height:1em from HTML preprocessing AND removing the height calculation in prepareHTMLElementForReaderRendering, footnote images might render with incorrect aspect ratio if originalSize is not available.
Why it happens: Some images in EPUBs may not have width/height attributes, so originalSize could be CGSizeZero.
How to avoid: DTCoreText's setDisplaySize:withMaxDisplaySize: (line 218-237 of DTTextAttachment.m) handles the case where originalSize has width but not height (and vice versa) by calculating from aspect ratio. If originalSize is completely zero, the image falls back to the DTMaxImageSize constraint. This should be safe, but verify with the demo sample.
Warning signs: Footnote images appearing at 0x0 or unreasonably large sizes.
Pitfall 3: Cover Image Double-Scaling
What goes wrong: The unified max-size block scales the image, then the cover-specific block scales it again, resulting in an image that's too small.
Why it happens: Two sequential scaling operations compound.
How to avoid: The cover-specific block in prepareHTMLElementForReaderRendering already uses UIScreen.main.bounds.insetBy(dx: 20, dy: 28) as its max, which is approximately 353x757 points. This is SMALLER than 1080x1920. So the unified max-size block will be a no-op for cover images (they're already within bounds). The cover block then applies its own tighter constraint. This is correct behavior — no double-scaling occurs.
Warning signs: Cover images appearing smaller than expected.
Pitfall 4: normalizeAttachmentDisplayIfNeeded Still Overrides
What goes wrong: After fixing prepareHTMLElementForReaderRendering, the normalizeAttachmentDisplayIfNeeded function (called from normalizeReadingAttributes) still overrides footnote and cover sizes.
Why it happens: This function runs AFTER willFlushCallback in the pipeline.
How to avoid: Per D-08/D-09, remove the footnote height override in this function too. The cover path in this function can remain as a fallback (it uses maxWidth = max(UIScreen.main.bounds.width - 48, font.lineHeight * 8) which is similar to the cover block in prepareHTMLElementForReaderRendering).
Warning signs: If footnote images still appear at wrong size after the fix, this function is the likely culprit.
Code Examples
WXRead Reference: _WRPostProcessElementTree (Objective-C)
// Source: Doc/WXRead/decompiled/WREpubTypesetter.m §672-701
if (element.textAttachment) {
DTTextAttachment *attachment = element.textAttachment;
CGSize maxSize = CGSizeMake(1080, 1920);
NSNumber *maxW = options[@"maxImageWidth"];
if (maxW) maxSize.width = maxW.floatValue;
if (attachment.originalSize.width > maxSize.width) {
CGFloat scale = maxSize.width / attachment.originalSize.width;
attachment.displaySize = CGSizeMake(
attachment.originalSize.width * scale,
attachment.originalSize.height * scale
);
}
element.textAttachment.attributes = @{
WREpubTypesetterVerticalCenterStyleAttribute: @(2)
};
[element addClass:@"bodyPic"];
}
Key observations:
- Max size is applied to ALL images, unconditionally (no class check)
- Only width is checked against max (
originalSize.width > maxSize.width), not height bodyPicclass is auto-added to every imagewr-vertical-center-style: 2is set on every image
DTCoreText's setDisplaySize:withMaxDisplaySize: (Objective-C)
// Source: ReadViewDemo/Pods/DTCoreText/Core/Source/DTTextAttachment.m §216-245
- (void)setDisplaySize:(CGSize)displaySize withMaxDisplaySize:(CGSize)maxDisplaySize {
if (_originalSize.width!=0 && _originalSize.height!=0) {
if (displaySize.width==0 && displaySize.height==0) {
displaySize = _originalSize;
} else if (displaySize.width==0 && displaySize.height!=0) {
CGFloat factor = _originalSize.height / displaySize.height;
displaySize.width = round(_originalSize.width / factor);
} else if (displaySize.width!=0 && displaySize.height==0) {
CGFloat factor = _originalSize.width / displaySize.width;
displaySize.height = round(_originalSize.height / factor);
}
}
if (maxDisplaySize.width>0 && maxDisplaySize.height>0) {
if (maxDisplaySize.width < displaySize.width || maxDisplaySize.height < displaySize.height) {
displaySize = DTCGSizeThatFitsKeepingAspectRatio(displaySize, maxDisplaySize);
}
}
}
Key observation for footnote width-only approach: When displaySize.width != 0 and displaySize.height == 0, DTCoreText calculates height from the aspect ratio. This means setting only width:1em in CSS (which translates to a display width) will automatically produce correct height. This confirms D-07 is safe.
Recommended: Updated prepareHTMLElementForReaderRendering
// Source: Sources/RDReaderView/EPUBTextRendering/RDEPUBTextRendererSupport.swift §217-262
static func prepareHTMLElementForReaderRendering(
_ element: DTHTMLElement,
style: RDEPUBTextRenderStyle
) {
guard let attachment = element.textAttachment else { return }
// --- NEW: Unified max image size (WXRead alignment) ---
let maxImageSize = CGSize(width: 1080, height: 1920)
let originalSize = attachment.originalSize
if originalSize.width > 0, originalSize.height > 0,
(originalSize.width > maxImageSize.width || originalSize.height > maxImageSize.height) {
let scale = min(maxImageSize.width / originalSize.width,
maxImageSize.height / originalSize.height)
attachment.displaySize = CGSize(
width: round(originalSize.width * scale),
height: round(originalSize.height * scale)
)
}
let lowercasedClasses = (((attachment.attributes["class"] as? String)
?? (element.attributes["class"] as? String) ?? "")).lowercased()
let lowercasedPath = attachment.contentURL?.lastPathComponent.lowercased()
?? ((attachment.attributes["src"] as? String)
?? (element.attributes["src"] as? String) ?? "").lowercased()
let pointSize = max(element.fontDescriptor.pointSize, style.font.pointSize)
// Footnote: width-only sizing, no explicit height (WXRead alignment)
if lowercasedClasses.contains("qqreader-footnote") || lowercasedPath == "note.png" {
attachment.verticalAlignment = .center
element.displayStyle = .inline
// Note: NO height calculation here. Width is set via HTML preprocessing
// (normalizeAttachmentHTMLMarkers adds width:1em). DTCoreText calculates
// height from aspect ratio automatically.
if !didLogFootnoteAttachment {
didLogFootnoteAttachment = true
print("[EPUB][Attachment] footnote classes=\(lowercasedClasses) path=\(lowercasedPath) original=\(string(from: originalSize)) display=\(string(from: attachment.displaySize)) font=\(pointSize)")
}
return
}
// Cover: screen-size base, already constrained by unified max above
if lowercasedClasses.contains("rd-front-cover-image") || lowercasedPath == "cover.jpg" {
let maxSize = UIScreen.main.bounds.insetBy(dx: 20, dy: 28).size
let currentOriginalSize = attachment.originalSize
if currentOriginalSize.width > 0, currentOriginalSize.height > 0 {
let scale = min(maxSize.width / currentOriginalSize.width, maxSize.height / currentOriginalSize.height)
if scale < 1.0 { // Only re-scale if larger than screen
attachment.displaySize = CGSize(
width: round(currentOriginalSize.width * scale),
height: round(currentOriginalSize.height * scale)
)
}
} else {
attachment.displaySize = CGSize(width: round(maxSize.width), height: round(maxSize.height))
}
attachment.verticalAlignment = .baseline
element.displayStyle = .block
if !didLogCoverAttachment {
didLogCoverAttachment = true
print("[EPUB][Attachment] cover classes=\(lowercasedClasses) path=\(lowercasedPath) original=\(string(from: currentOriginalSize)) display=\(string(from: attachment.displaySize))")
}
}
}
State of the Art
| Old Approach | Current Approach | When Changed | Impact |
|---|---|---|---|
| DTMaxImageSize = screen bounds | DTMaxImageSize = 1080x1920 | This phase | All images get correct ceiling at creation time |
| Footnote: explicit height calc (0.54pt in renderer, 0.14pt in view) | Footnote: width-only from CSS, height auto-calculated | This phase | Consistent with WXRead, simpler, no conflicting overrides |
| Cover: screen-size only, no unified max | Cover: screen-size + unified max ceiling | This phase | Rare edge case: very large cover images get proper constraint |
| qrbodyPic: no max constraint | qrbodyPic: constrained by unified max | This phase | Fixes height overflow for image-heavy chapters |
Deprecated/outdated:
pointSize * 0.54footnote height calculation inprepareHTMLElementForReaderRendering— replaced by width-only approachpointSize * 0.14footnote height override innormalizeInlineAttachments— removed entirelypointSize * 0.14footnote height override innormalizeAttachmentDisplayIfNeeded— removed entirely
Assumptions Log
| # | Claim | Section | Risk if Wrong |
|---|---|---|---|
| A1 | DTCoreText correctly calculates height from aspect ratio when only width is set on an attachment (verified via DTTextAttachment.m source code reading) | Pattern 2: Footnote Width-Only | LOW — code at line 231-236 explicitly handles this case |
| A2 | WXRead's _WRPostProcessElementTree checks only width, not height, against maxSize (verified via decompiled source) |
WXRead Reference | LOW — source code at line 680 confirms originalSize.width > maxSize.width |
| A3 | The normalizeAttachmentDisplayIfNeeded function at line 467-505 of RDEPUBTextRendererSupport.swift needs its footnote height override removed (per D-08/D-09) |
Pitfall 4 | MEDIUM — if not removed, it will override the willFlushCallback changes |
Open Questions
-
Should we also update
DTMaxImageSizeindtOptions()from screen bounds to 1080x1920?- What we know:
dtOptions()currently usesUIScreen.main.bounds.insetBy(dx: 20, dy: 28).size(~353x757) - What's unclear: Whether changing this affects non-image attachments or has side effects
- Recommendation: Yes, update to
CGSize(width: 1080, height: 1920). This is the first-pass constraint at attachment creation time. The willFlushCallback block is the authoritative second pass. Aligning both to the same max size eliminates confusion.
- What we know:
-
Should we auto-add
bodyPicclass to all images like WXRead does?- What we know: WXRead adds
bodyPicclass to every image in_WRPostProcessElementTree - What's unclear: Whether ReadViewSDK's CSS rules depend on
bodyPicbeing present for proper centering - Recommendation: Not required for the immediate fix. The
replaceCSSalready handlesimg, svg, video, canvaswithmax-width: 100%; height: auto, and specific selectors like.bodyPic imgfor centering. Adding the class would be a nice-to-have for full WXRead alignment but is not blocking.
- What we know: WXRead adds
-
Should
normalizeAttachmentDisplayIfNeeded(line 467-505) be updated or removed entirely?- What we know: This function runs in
normalizeReadingAttributes(post-willFlushCallback) and overrides footnote/cover sizes - What's unclear: Whether removing the footnote path is sufficient, or whether the cover path should also be simplified
- Recommendation: Remove the footnote height override path (D-08). The cover path can remain as a fallback since it produces similar results to the
prepareHTMLElementForReaderRenderingcover block.
- What we know: This function runs in
Environment Availability
No external dependencies required — all changes are to existing Swift source files.
| Dependency | Required By | Available | Version | Fallback |
|---|---|---|---|---|
| Xcode / Swift compiler | Build & run | ✓ | (project toolchain) | — |
| DTCoreText (CocoaPod) | Image attachment API | ✓ | (project-local) | — |
| Demo EPUB sample | Visual verification | ✓ | 宝山辽墓材料与释读 | — |
Missing dependencies with no fallback: None Missing dependencies with fallback: None
Validation Architecture
Test Framework
| Property | Value |
|---|---|
| Framework | None (no unit test target for EPUBTextRendering) |
| Config file | none |
| Quick run command | xcodebuild build -project ReadViewDemo/ReadViewDemo.xcodeproj -scheme ReadViewDemo -destination 'platform=iOS Simulator,name=iPhone 16' |
| Full suite command | Same as quick run (build-only verification) |
Phase Requirements → Test Map
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|---|---|---|---|---|
| QUAL-02 | Images don't overflow page | manual visual | Build + run demo + navigate to 图文章节 | N/A |
| QUAL-03 | Image sizing rules are verifiable | code review | Verify max-size constant is 1080x1920 | N/A |
| QUAL-04 | No performance degradation | manual timing | Compare pagination time before/after | N/A |
Sampling Rate
- Per task commit:
xcodebuild build(compilation check) - Per wave merge: Build + run demo + visual inspection of 图文章节
- Phase gate: Visual verification that all three image types display correctly
Wave 0 Gaps
- No automated image size assertion tests — manual visual verification required
- No snapshot/regression test infrastructure for image rendering
Sources
Primary (HIGH confidence)
Doc/WXRead/decompiled/WREpubTypesetter.m§672-701 —_WRPostProcessElementTreemax size logicDoc/WXRead/decompiled/WRCoreTextLayoutFrame.m§615-635 — cover image drawingDoc/WXRead/resources/css/replace.css§91-103 —.bodyPic,.qrbodyPic,.qqreader-footnoteCSSSources/RDReaderView/EPUBTextRendering/RDEPUBTextRendererSupport.swift§217-262, §302-343, §345-404, §467-505 — current implementationReadViewDemo/Pods/DTCoreText/Core/Source/DTTextAttachment.m§216-245 —setDisplaySize:withMaxDisplaySize:implementationReadViewDemo/Pods/DTCoreText/Core/Source/DTTextAttachment.h—originalSize,displaySize,verticalAlignmentAPI
Secondary (MEDIUM confidence)
ReadViewDemo/ReadViewDemo/book/宝山辽墓材料与释读_副本/OEBPS/Text/Chapter_5.xhtml—qrbodyPicHTML structureReadViewDemo/ReadViewDemo/book/宝山辽墓材料与释读_副本/OEBPS/Text/cover.xhtml— cover HTML structureReadViewDemo/ReadViewDemo/book/宝山辽墓材料与释读_副本/OEBPS/Styles/stylesheets.css— EPUB's own CSS rules
Metadata
Confidence breakdown:
- Standard stack: HIGH — DTCoreText is the existing project dependency, API is well-understood
- Architecture: HIGH — pipeline is clearly documented, code paths are traced
- Pitfalls: HIGH — all pitfalls identified from direct source code reading
Research date: 2026-05-23 Valid until: 2026-06-23 (stable — DTCoreText and project code are not changing rapidly)