Created
April 22, 2021 07:18
-
-
Save owulveryck/ae2e071bd5740c96bdc92c7f8f8f7172 to your computer and use it in GitHub Desktop.
Reading the .line format from the reMarkable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/binary" | |
"errors" | |
"fmt" | |
"image" | |
"io" | |
"log" | |
"os" | |
"strings" | |
) | |
// https://remarkablewiki.com/tech/filesystem?s[]=lines | |
// and https://plasma.ninja/blog/devices/remarkable/binary/format/2017/12/26/reMarkable-lines-file-format.html | |
func (p *Page) String() string { | |
return p.Header | |
} | |
type Page struct { | |
Header string | |
Layers []*Layer | |
} | |
type Layer struct { | |
Strokes []*Stroke | |
} | |
type Stroke struct { | |
Pen uint32 | |
StrokeColor uint32 | |
PenWidth float32 | |
Segments []*Segment | |
} | |
type Segment struct { | |
P image.Point | |
Speed float32 | |
Direction float32 | |
Width float32 | |
Pressure float32 | |
} | |
func main() { | |
p := &Page{} | |
err := Read(os.Stdin, p) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fmt.Println(p) | |
} | |
func Read(r io.Reader, p *Page) error { | |
return p.readFrom(r) | |
} | |
// readFrom r and fill p | |
func (p *Page) readFrom(r io.Reader) error { | |
var buf struct { | |
Header [43]byte | |
NumLayers int32 | |
} | |
err := binary.Read(r, binary.LittleEndian, &buf) | |
if err != nil { | |
return err | |
} | |
p.Header = string(buf.Header[:]) | |
if !strings.Contains(p.Header, "version=5") { | |
return errors.New("only version 5 is supported") | |
} | |
p.Layers = make([]*Layer, buf.NumLayers) | |
for i := 0; i < int(buf.NumLayers); i++ { | |
p.Layers[i] = &Layer{} | |
err := p.Layers[i].readFrom(r) | |
if err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
// readFrom r and fill l | |
func (l *Layer) readFrom(r io.Reader) error { | |
var numStrokes int32 | |
err := binary.Read(r, binary.LittleEndian, &numStrokes) | |
if err != nil { | |
return err | |
} | |
l.Strokes = make([]*Stroke, numStrokes) | |
for i := 0; i < int(numStrokes); i++ { | |
l.Strokes[i] = &Stroke{} | |
err := l.Strokes[i].readFrom(r) | |
if err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
func (s *Stroke) readFrom(r io.Reader) error { | |
var buf struct { | |
Pen int32 | |
Color int32 | |
_ int32 | |
Width float32 | |
_ int32 | |
NumSegments int32 | |
} | |
err := binary.Read(r, binary.LittleEndian, &buf) | |
if err != nil { | |
return err | |
} | |
s.Pen = uint32(buf.Pen) | |
s.StrokeColor = uint32(buf.Color) | |
s.PenWidth = float32(buf.Width) | |
s.Segments = make([]*Segment, buf.NumSegments) | |
for i := 0; i < int(buf.NumSegments); i++ { | |
s.Segments[i] = &Segment{} | |
err := s.Segments[i].readFrom(r) | |
if err != nil { | |
return err | |
} | |
} | |
return nil | |
} | |
func (s *Segment) readFrom(r io.Reader) error { | |
var buf struct { | |
X float32 | |
Y float32 | |
Speed float32 | |
Direction float32 | |
Width float32 | |
Pressure float32 | |
} | |
err := binary.Read(r, binary.LittleEndian, &buf) | |
if err != nil { | |
return err | |
} | |
s.P.X = int(buf.X) | |
s.P.Y = int(buf.Y) | |
if !s.P.In(image.Rect(0, 0, 1404, 1872)) { | |
return fmt.Errorf("point %v is out of bound", s.P) | |
} | |
s.Speed = buf.Speed | |
s.Direction = buf.Direction | |
s.Width = buf.Width | |
s.Pressure = buf.Pressure | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment