Skip to content

Conversation

@joagonca
Copy link
Contributor

  • Supports rendering reMarkable v6 files w/ colour and all pen types, including text.
  • Rendering is supported in Go, using go-cairo to produce the PDF contents (implementation in this library: https://github.com/joagonca/rmc-go). Highly based on rmscene, with added functionality (like colour support).
  • Ability to export/download to PDF the .RM file.
  • [CAVEAT] For now it only supports rendering the first page.

Trying to address issue #255 .

@joagonca joagonca mentioned this pull request Oct 29, 2025
@baflo
Copy link

baflo commented Oct 31, 2025

Awesome work @joagonca 🥳
However, am I doing something wrong? It always shows just one page and it's not deterministic which one is rendered...

@joagonca
Copy link
Contributor Author

Thanks!
That is correct, it's a limitation of the current integration. There is already support for a multipage render on the library, but I wanted to keep this initial PR simple (just v6 support).

The "randomness", I intend to fix that, and support all pages in a subsequent PR. The rmc-go library already exports the multipage PDF using the .content files from reMarkable, in the correct order.

@joagonca
Copy link
Contributor Author

joagonca commented Nov 3, 2025

It should now support multipage rendering in the correct order.
Still one caveat: some pages might appear cropped (I'm calculating the PDF page size based on the first .rm file).

@baflo

@baflo
Copy link

baflo commented Nov 3, 2025

@joagonca I actually came up with a solution myself, too. I looks quite similar to yours, but it stitches the single pages together with unipdf, so all pages maintain their original size. Maybe it is of help to you:

baflo@15de3ca#diff-fc741d1c044272840de20d525e88fb8068c4737e42703b589317c2f981502d12

@joagonca
Copy link
Contributor Author

joagonca commented Nov 3, 2025

@baflo Nice one. For the sake of this PR, it might make more sense to go with yours, as it provides best functionality out of the box.

For the final one, I might ditch go-cairo and go with unipdf in the library. That way the whole packaging will use just one Go PDF renderer, and we'd remove the cgo requirement.

Thoughts?

@baflo
Copy link

baflo commented Nov 3, 2025

Sound good to me ;)

@ddvk what do you think?

@ddvk ddvk requested a review from Copilot November 3, 2025 12:31
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds native support for reMarkable v6 file format (introduced in software 3.0+) to rmfakecloud. The implementation integrates the rmc-go library with Cairo renderer to enable in-process rendering of v6 files without external dependencies.

Key changes:

  • Added version detection logic to differentiate between v3/v5/v6 .rm file formats
  • Integrated rmc-go library for native v6 file rendering using Cairo
  • Updated document export paths to route v5 files to rmapi and v6 files to rmc-go

Reviewed Changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/storage/models/archive.go Modified to detect and store v6 page data separately in V6PageData map instead of attempting to parse with rmapi
internal/storage/fs/documents.go Added version detection and routing logic to use rmc-go for v6 files and rmapi for v5 files
internal/storage/fs/blobstore.go Implemented v6 blob export path with direct .rm file extraction and rmc-go rendering
internal/storage/exporter/version.go New file with version detection logic for .rm files
internal/storage/exporter/version_test.go Comprehensive tests for version detection functionality
internal/storage/exporter/rmc_go.go New file with wrapper functions for rmc-go library PDF/SVG export
internal/storage/exporter/myarchive.go Added V6PageData field to store raw v6 page bytes
internal/config/config.go Updated help text to document v6 support and formatting fix
go.mod Added rmc-go dependency and upgraded Go version to 1.25.1
go.sum Updated with new dependencies (rmc-go and go-cairo)
README.md Added comprehensive v6 support documentation
Makefile Added build-cairo targets for building with Cairo support
Dockerfile Updated to include Cairo dependencies for v6 rendering

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 722 to 735
if len(arch.Pages) == 0 {
return exporter.VersionUnknown, fmt.Errorf("no pages in archive")
}

// Try to marshal first page and detect from header
if arch.Pages[0].Data != nil {
data, err := arch.Pages[0].Data.MarshalBinary()
if err != nil {
return exporter.VersionUnknown, fmt.Errorf("failed to marshal page data: %w", err)
}
return exporter.DetectRmVersion(bytes.NewReader(data))
}

return exporter.VersionUnknown, fmt.Errorf("no page data available")
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

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

The function 'detectBlobArchiveVersion' is identical to 'detectArchiveVersion' in documents.go (lines 227-243). This is duplicated code. Consider extracting this to a shared utility function or moving it to the exporter package to avoid duplication.

Suggested change
if len(arch.Pages) == 0 {
return exporter.VersionUnknown, fmt.Errorf("no pages in archive")
}
// Try to marshal first page and detect from header
if arch.Pages[0].Data != nil {
data, err := arch.Pages[0].Data.MarshalBinary()
if err != nil {
return exporter.VersionUnknown, fmt.Errorf("failed to marshal page data: %w", err)
}
return exporter.DetectRmVersion(bytes.NewReader(data))
}
return exporter.VersionUnknown, fmt.Errorf("no page data available")
return exporter.DetectArchiveVersionFromMyArchive(arch)

Copilot uses AI. Check for mistakes.
README.md Outdated

### Known Limitations

- Multi-page v6 documents: Currently exports first page only
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

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

The documentation states 'Multi-page v6 documents: Currently exports first page only' in Known Limitations, but the code in documents.go (lines 122-127) and blobstore.go (lines 194-212) clearly iterates through all pages and uses ExportV6MultiPageToPdfNative to export all pages. This limitation appears to be incorrect or outdated.

Suggested change
- Multi-page v6 documents: Currently exports first page only
- Multi-page v6 documents: Fully supported

Copilot uses AI. Check for mistakes.
Comment on lines 123 to 127
for i := 0; i < len(arch.V6PageData); i++ {
if data, ok := arch.V6PageData[i]; ok {
pages = append(pages, data)
}
}
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

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

This loop assumes that V6PageData keys are sequential from 0 to len(V6PageData)-1, but if there are gaps in the page indices (e.g., missing page 2 in a 5-page document), the loop will still iterate 5 times but may skip entries. This could result in pages being collected out of order or missing pages. Consider using a sorted iteration over the map keys instead.

Copilot uses AI. Check for mistakes.
@ddvk
Copy link
Owner

ddvk commented Nov 3, 2025

nice work!

unipdf is no longer agpl and has to be removed

@joagonca
Copy link
Contributor Author

joagonca commented Nov 3, 2025

Hmm, if that's the case, we might be better off trying to fix it using current go-cairo implementation. I can take that task on the library side. Then see if updating the package here fixes the issue.

Moreover, I'll address the comments made by co-pilot.

@joagonca
Copy link
Contributor Author

joagonca commented Nov 3, 2025

I've bumped the rmc-go library to v1.1.1 which already supports multi-size multi-page PDF rendering using go-cairo. I think I've also addressed the co-pilot comments.

@rmitchellscott
Copy link
Contributor

A quick look seems to indicate that this also will support CRDT IDs needed for the handwriting search branch I'm working on 👍

@ericchianti
Copy link

Do we have an estimate on how long is left on this PR before it gets merged? I am so thrilled for this ticket I check several times a week.

@baflo
Copy link

baflo commented Jan 6, 2026

@ddvk I would like to help rectify any problems that still exist with this PR. Would you give me a hint what's missing so this can be merged?

@ddvk
Copy link
Owner

ddvk commented Jan 6, 2026

just the merge conflicts i guess

@joagonca
Copy link
Contributor Author

joagonca commented Jan 6, 2026 via email

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.

5 participants