The Sony PRS-350 remains a wonderful eReader after many years (and it's cheap on eBay!) and I am pleased to report that, despite its age, some Ruby exists to extract annotations.

After attempts to save annotations using Kovid Goyal's tremendous Calibre with the Calibre-Annotations plug-in, it was eventually discovered that the PRS-350 annotation saving is a bit different from what later Sony readers and other current readers employ. I then stumbled upon Elie Morisse's PRSAnnotationExtractor – now eight years past any updates and written around (it seems) a later Sony Reader (at least the PRS-650, as reported for testing).
Fortunately, with the right installs in place, PRSAnnotationExtractor works just fine to process book annotations provided both the epub and the annot files are in the right place, both of which are accessible from the mounted PRS-350 device on your desktop.
Qualifiers
- The process below works just fine under Ubuntu 18.04.5 LTS and should work just fine for others.
- The install process and associated errors from a semi-fresh Ubuntu install are included under the assumption that someone searching for how to install PRSAnnotationExtractor is getting the same errors.
Ruby Installs
Working from the requirements listed on the PRSAnnotationExtractor page, you need nokogiri, csspool, and zipruby …
Install and failure of nokogiri …
user@machine:~$ sudo gem install nokogiri
Fetching: racc-1.5.2.gem (100%)
Building native extensions. This could take a while...
ERROR: Error installing nokogiri:
ERROR: Failed to build gem native extension.
current directory: /var/lib/gems/2.5.0/gems/racc-1.5.2/ext/racc/cparse
/usr/bin/ruby2.5 -r ./siteconf20210719-2367-hgn9lr.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h
extconf failed, exit code 1
Gem files will remain installed in /var/lib/gems/2.5.0/gems/racc-1.5.2 for inspection.
Results logged to /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/racc-1.5.2/gem_make.out
… because you've not the necessary Ruby files installed by default (ruby2.5-dev or whatever the available version is in that range).
user@machine:~$ sudo apt-get install ruby2.5-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
...
Setting up ruby2.5-dev:amd64 (2.5.1-1ubuntu1.9) ...
Processing triggers for libc-bin (2.27-3ubuntu1.4) ...
With ruby2.5-dev installed …
user@machine:~$ sudo gem install nokogiri
Building native extensions. This could take a while...
Successfully installed racc-1.5.2
Fetching: nokogiri-1.11.7-x86_64-linux.gem (100%)
Successfully installed nokogiri-1.11.7-x86_64-linux
Parsing documentation for racc-1.5.2
Installing ri documentation for racc-1.5.2
Parsing documentation for nokogiri-1.11.7-x86_64-linux
Installing ri documentation for nokogiri-1.11.7-x86_64-linux
Done installing documentation for racc, nokogiri after 2 seconds
2 gems installed
… goes without issue, as does csspool.
user@machine:~$ sudo gem install csspool
Fetching: csspool-4.0.5.gem (100%)
Successfully installed csspool-4.0.5
Parsing documentation for csspool-4.0.5
Installing ri documentation for csspool-4.0.5
Done installing documentation for csspool after 0 seconds
1 gem installed
An initial zipruby install produced the error below …
user@machine:~$ sudo gem install zipruby
Fetching: zipruby-0.3.6.gem (100%)
Building native extensions. This could take a while...
ERROR: Error installing zipruby:
ERROR: Failed to build gem native extension.
current directory: /var/lib/gems/2.5.0/gems/zipruby-0.3.6/ext
/usr/bin/ruby2.5 -r ./siteconf20210719-3294-m0tqur.rb extconf.rb
checking for zlib.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers. Check the mkmf.log file for more details. You may
need configuration options.
Provided configuration options:
--with-opt-dir
--without-opt-dir
--with-opt-include
--without-opt-include=${opt-dir}/include
--with-opt-lib
--without-opt-lib=${opt-dir}/lib
--with-make-prog
--without-make-prog
--srcdir=.
--curdir
--ruby=/usr/bin/$(RUBY_BASE_NAME)2.5
To see why this extension failed to compile, please check the mkmf.log which can be found here:
/var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/mkmf.log
extconf failed, exit code 1
Gem files will remain installed in /var/lib/gems/2.5.0/gems/zipruby-0.3.6 for inspection.
Results logged to /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/gem_make.out
… which, upon inspection, is due to missing zlib.h.
user@machine:~$ more /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/mkmf.log
have_header: checking for zlib.h... -------------------- no
"gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-2.5.0 -I/usr/include/ruby-2.5.0/ruby/backward -I/usr/include/ruby-2.5.0 -I. -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fdebug-prefix-map=/build/r
uby2.5-FWwz7w/ruby2.5-2.5.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC conftest.c -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack
-protector -rdynamic -Wl,-export-dynamic -lruby-2.5 -lpthread -lgmp -ldl -lcrypt -lm -lc"
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: int main(int argc, char **argv)
4: {
5: return 0;
6: }
/* end */
"gcc -E -I/usr/include/x86_64-linux-gnu/ruby-2.5.0 -I/usr/include/ruby-2.5.0/ruby/backward -I/usr/include/ruby-2.5.0 -I. -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fdebug-prefix-map=/build/ruby2.5-FW
wz7w/ruby2.5-2.5.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC conftest.c -o conftest.i"
conftest.c:3:10: fatal error: zlib.h: No such file or directory
#include <zlib.h>
^~~~~~~~
compilation terminated.
checked program was:
/* begin */
1: #include "ruby.h"
2:
3: #include <zlib.h>
/* end */
--------------------
Install of zlib1g-dev solves this issue …
user@machine:~$ sudo apt install zlib1g-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
...
Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
… and zipruby now cleanly installs.
user@machine:~$ sudo gem install zipruby
Building native extensions. This could take a while...
Successfully installed zipruby-0.3.6
Parsing documentation for zipruby-0.3.6
Installing ri documentation for zipruby-0.3.6
Done installing documentation for zipruby after 0 seconds
1 gem installed
PRSAnnotationExtractor
Now, with the PRSAnnotationExtractor-master.zip downloaded (click the green "Code" and "Download Zip"), we expand …
user@machine:~$ unzip PRSAnnotationExtractor-master.zip
Archive: PRSAnnotationExtractor-master.zip
66f0b284ed662ffd939f4608ac15c375f635b3a1
creating: PRSAnnotationExtractor-master/
inflating: PRSAnnotationExtractor-master/.gitignore
...
inflating: PRSAnnotationExtractor-master/prsannotextract.rb
inflating: PRSAnnotationExtractor-master/screenshot.png
… and confirm contents:
user@machine:~$ cd PRSAnnotationExtractor-master/
user@machine:~/PRSAnnotationExtractor-master$ ls -l
total 116
drwxrwxr-x 7 user user 4096 Oct 22 2013 csspool
-rw-rw-r-- 1 user user 488 Oct 22 2013 csspool.rb
-rw-rw-r-- 1 user user 15292 Oct 22 2013 inlineparser.rb
-rw-rw-r-- 1 user user 4028 Oct 22 2013 inlineparser.y
-rw-rw-r-- 1 user user 7066 Oct 22 2013 inlinetokenizer.rb
-rw-rw-r-- 1 user user 3661 Oct 22 2013 inlinetokenizer.rex
-rw-rw-r-- 1 user user 1079 Oct 22 2013 LICENSE
-rw-rw-r-- 1 user user 1110 Oct 22 2013 LICENSE.csspool
-rwxr-xr-x 1 user user 15905 Oct 22 2013 prsannotextract.rb
-rw-rw-r-- 1 user user 1848 Oct 22 2013 README.md
-rw-rw-r-- 1 user user 47437 Oct 22 2013 screenshot.png
Usage And Tweak
To run, you copy the .epub and .annot files for the epub into the folder containing prsannotextract.rb and:
ruby prsannotextract.rb book.epub.annot book.epub
Upon mounting the PRS-350, your book location and annotation location are:
Reader > database > media > books
Reader > Digital Editions > Annotations > database > media > books
For ease, simply copy the book and annotation files into the PRSAnnotationExtractor-master folder. That said, first execution on my sample book (out of the PRS-350-formatted .annot file) produced the following:
user@machine:~/PRSAnnotationExtractor-master$ ruby prsannotextract.rb book.epub.annot book.epub
Traceback (most recent call last):
23: from prsannotextract.rb:535:in `<main>'
22: from prsannotextract.rb:410:in `extract'
21: from prsannotextract.rb:410:in `new'
20: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:296:in `initialize'
19: from prsannotextract.rb:421:in `block in extract'
18: from prsannotextract.rb:421:in `open'
17: from prsannotextract.rb:428:in `block (2 levels) in extract'
16: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
15: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
14: from prsannotextract.rb:443:in `block (3 levels) in extract'
13: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
12: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
11: from prsannotextract.rb:446:in `block (4 levels) in extract'
10: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:238:in `each'
9: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:238:in `upto'
8: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:239:in `block in each'
7: from prsannotextract.rb:449:in `block (5 levels) in extract'
6: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
5: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
4: from prsannotextract.rb:456:in `block (6 levels) in extract'
3: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
2: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
1: from prsannotextract.rb:489:in `block (7 levels) in extract'
prsannotextract.rb:349:in `wraptext': invalid byte sequence in UTF-8 (ArgumentError
This issue here, which I address without proper workup, is due to lines 349 – 351 in prsannotextract.rb – the UTF-8 error is not an error for the purposes of extracting the annotations from the PRS-350 (again, something must have changed in the PRS-650 and similar devices). Simply commenting out the block of lines (add the #'s) in a text editor …
# if not /[^\s]/ =~ text
# return
# end
… yields a working annotation extraction program – which, initially, writes to the terminal.
user@machine:~/PRSAnnotationExtractor-master$ ruby prsannotextract.rb book.epub.annot book.epub
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
<style>
div#wrapper { margin:0 auto; background-color:#d8d880; }
div.Annotation { margin:10px 0; border:thin dotted #080808; background-color:#f2f2ff; max-width:750px; }
div.AnnotationTitle { margin-left:2px; }
span.AnnotTitle { font-weight:bold; }
span.AnnotDate { font-size:90%; color:sienna; }
div.AnnotationBody { margin-left:8px; margin-top:3px; }
</style>
</head>
<body>
<div class="Annotation">
<div class="AnnotationTitle">
<span class="AnnotTitle">Elevate</span>
<span class="AnnotDate">2010-01-02 10:45:34</span>
</div>
<div class="AnnotationBody">
<p>
<span style="font-size:0.875em;">zeitgeist </span>
</p>
</div>
</div>
<div class="Annotation">
<div class="AnnotationTitle">
<span class="AnnotTitle">Elevate</span>
<span class="AnnotDate">2010-01-02 11:11:14</span>
</div>
<div class="AnnotationBody">
<p>
<span style="font-size:0.875em;">Annotation... </span>
</p>
</div>
</div>
</body>
</html>
Simply redirect to book.html and your annotations are visible and cleanly formatted.
ruby prsannotextract.rb book.epub.annot book.epub > book.html