Skip to content

Normalize problematic EPUB image sizing#41

Open
thiagokokada wants to merge 2 commits into
crosspoint-reader:masterfrom
thiagokokada:fix-crosspoint-image-sizing
Open

Normalize problematic EPUB image sizing#41
thiagokokada wants to merge 2 commits into
crosspoint-reader:masterfrom
thiagokokada:fix-crosspoint-image-sizing

Conversation

@thiagokokada

@thiagokokada thiagokokada commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Normalize inline EPUB image sizing during CrossPoint optimization.
  • Strip width / height attributes from <img> tags as before.
  • Also strip inline width / height declarations from <img style="...">.
  • Keep stylesheet/CSS-resource handling unchanged apart from existing image reference renaming.

Problem

Some EPUBs include inline image sizing that overrides CrossPoint’s defensive responsive image CSS.

Example:

<img
  src="../Images/Art_P12.jpg"
  style="max-height: 100%; max-width: 100%; width: auto; height: 98vh;"
/>

The optimizer already injects:

img,svg{max-width:100%;height:auto}

But inline width / height declarations have higher precedence, so values like height: 98vh can prevent optimized images from rendering at the expected size.

Fix

When rewriting XHTML, the optimizer now removes any inline width or height declaration from <img style="...">, while preserving unrelated style declarations.

This mirrors the existing behavior for width= and height= attributes and keeps the change scoped to inline image markup.

Validation

  • Verified against the affected Re:ZERO Vol. 01 EPUB.
  • Confirmed XHTML no longer contains the problematic inline image sizing.
  • Verified on Xteink X4 that affected images render at the expected size.

Notes

  • I didn't test this fix with lots of books, so this can cause some unforeseen issues.
  • This same bug affects the optimizer in the Crosspoint web page too, so if this is accepted this should probably also backported there.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@thiagokokada, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aba23967-9e80-4bef-af73-f1a53c5f4fee

📥 Commits

Reviewing files that changed from the base of the PR and between ef124ca and 73a703f.

📒 Files selected for processing (1)
  • crosspoint_reader/optimizer.py
📝 Walkthrough

Walkthrough

The EPUB optimizer adds shared helpers to remove image dimensions and sizing declarations, rewrite raster references, and apply the same normalization to namespaced and namespace-less XHTML images.

Changes

Image sizing normalization

Layer / File(s) Summary
Image normalization helpers
crosspoint_reader/optimizer.py
Adds helpers that remove width and height attributes and CSS declarations from image styles, while centralizing raster-reference rewriting.
XHTML optimizer integration
crosspoint_reader/optimizer.py
Updates _fix_xhtml to use the shared image helper for namespaced and namespace-less <img> elements.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: normalizing problematic EPUB image sizing.
Description check ✅ Passed The description is directly related to the XHTML image sizing normalization changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
crosspoint_reader/optimizer.py (2)

316-325: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Bypass string manipulation when the style attribute doesn't need modification.

Just like the logic in _fix_css, returning m.group(0) early when no declarations are problematic prevents unnecessary string rewriting and preserves the exact original whitespace in the document.

♻️ Proposed refactor
 def _fix_img_style_text(tag):
     def repl(m):
         quote = m.group(1)
         style = m.group(2)
-        fixed, _ = _fix_img_style_attr(style)
+        fixed, modified = _fix_img_style_attr(style)
+        if not modified:
+            return m.group(0)
         if fixed:
             return ' style=%s%s%s' % (quote, fixed, quote)
         return ''
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crosspoint_reader/optimizer.py` around lines 316 - 325, The
_fix_img_style_text replacement currently rewrites valid style attributes and
can alter their original formatting. Update repl to return m.group(0) when
_fix_img_style_attr reports no problematic declarations, while preserving the
existing rewritten output only when fixed contains a correction.

391-394: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use the bitwise OR assignment |= for safer boolean accumulation.

While modified = _fix_img_element(img) or modified is technically correct because Python evaluates the left operand first (ensuring the function runs), it relies on a subtle ordering detail that is easily broken during future refactoring. For example, flipping it to modified or _fix_img_element(...) would introduce a severe short-circuit bug where images stop being processed. Using |= is more idiomatic and eliminates this risk entirely.

♻️ Proposed refactor
-                modified = _fix_img_element(img) or modified
+                modified |= _fix_img_element(img)
             # also catch namespace-less <img> (malformed docs)
             for img in root.iter('img'):
-                modified = _fix_img_element(img) or modified
+                modified |= _fix_img_element(img)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crosspoint_reader/optimizer.py` around lines 391 - 394, Replace the boolean
accumulation assignments in the image-processing loops around _fix_img_element
with |=, preserving the call for every image while accumulating whether any
element was modified.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crosspoint_reader/optimizer.py`:
- Around line 316-325: The _fix_img_style_text replacement currently rewrites
valid style attributes and can alter their original formatting. Update repl to
return m.group(0) when _fix_img_style_attr reports no problematic declarations,
while preserving the existing rewritten output only when fixed contains a
correction.
- Around line 391-394: Replace the boolean accumulation assignments in the
image-processing loops around _fix_img_element with |=, preserving the call for
every image while accumulating whether any element was modified.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a383140-afb4-4203-a89a-a20fcc188098

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd9c7c and dd08ccd.

📒 Files selected for processing (1)
  • crosspoint_reader/optimizer.py

@thiagokokada thiagokokada marked this pull request as draft July 14, 2026 20:32
@thiagokokada thiagokokada force-pushed the fix-crosspoint-image-sizing branch from dd08ccd to a0d24fe Compare July 14, 2026 20:37
@thiagokokada thiagokokada force-pushed the fix-crosspoint-image-sizing branch from a0d24fe to ef124ca Compare July 14, 2026 20:40
@thiagokokada thiagokokada marked this pull request as ready for review July 14, 2026 20:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crosspoint_reader/optimizer.py`:
- Line 324: Update the style-attribute substitution in the optimizer’s re.sub
call to include re.DOTALL alongside re.IGNORECASE, so the existing non-greedy
capture matches style values spanning newlines while preserving current
normalization behavior.
- Around line 285-310: Update _filter_style_declarations to remove matching
declarations without naively splitting style by semicolons; use a regex-based
replacement that preserves semicolons and formatting inside quoted strings or
data URIs. Keep predicate-based filtering for width and height via
_is_problem_img_decl and preserve the function’s return value and modified flag
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 19509cda-073b-470a-9baa-be051bcd4524

📥 Commits

Reviewing files that changed from the base of the PR and between dd08ccd and ef124ca.

⛔ Files ignored due to path filters (1)
  • crosspoint_reader/__pycache__/optimizer.cpython-313.pyc is excluded by !**/*.pyc
📒 Files selected for processing (1)
  • crosspoint_reader/optimizer.py

Comment thread crosspoint_reader/optimizer.py
Comment thread crosspoint_reader/optimizer.py Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant